簡體   English   中英

逐字閱讀文本文件

[英]Reading a text file word by word

我有一個文本文件,只包含小寫字母,除空格外沒有標點符號。 我想知道通過char讀取文件char的最佳方法,如果下一個char是空格,它表示一個單詞的結尾和一個新單詞的開頭。 即,當每個字符被讀取時,它被添加到字符串中,如果下一個字符是空格,則該字被傳遞給另一個方法並重置,直到讀者到達文件的末尾。

我正在嘗試使用StringReader執行此操作,如下所示:

public String GetNextWord(StringReader reader)
{
    String word = "";
    char c;
    do
    {
        c = Convert.ToChar(reader.Read());
        word += c;
    } while (c != ' ');
    return word;
}

並將GetNextWord方法放在while循環中直到文件結束。 這種方法有意義還是有更好的方法來實現這一目標?

有一個更好的方法: string.Split() :如果你讀取整個字符串,C#可以自動在每個空間分割它:

string[] words = reader.ReadToEnd().Split(' ');

words數組現在包含文件中的所有單詞,您可以隨意使用它們。

此外,您可能希望調查System.IO命名空間中的File.ReadAllText方法 - 它可以使文件導入文本的生活更輕松。

編輯:我想這假設您的文件不是很大; 只要整個事物可以合理地讀入內存,這將最容易。 如果你有數千兆字節的數據要讀,你可能會想回避這一點。 我建議盡可能使用這種方法:它可以更好地利用您擁有的框架。

如果你對即使在非常大的文件上也有良好的性能感興趣,你應該看看新的(4.0) MemoryMappedFile -Class

例如:

using (var mappedFile1 = MemoryMappedFile.CreateFromFile(filePath))
{
    using (Stream mmStream = mappedFile1.CreateViewStream())
    {
        using (StreamReader sr = new StreamReader(mmStream, ASCIIEncoding.ASCII))
        {
            while (!sr.EndOfStream)
            {
                var line = sr.ReadLine();
                var lineWords = line.Split(' ');
            }
        }  
    }
}

來自MSDN:

內存映射文件將文件內容映射到應用程序的邏輯地址空間。 內存映射文件使程序員能夠處理非常大的文件,因為可以同時管理內存,並且它們允許完全隨機訪問文件而無需搜索。 內存映射文件也可以跨多個進程共享。

CreateFromFile方法從指定路徑或磁盤上現有文件的FileStream創建內存映射文件。 取消映射文件時,更改會自動傳播到磁盤。

CreateNew方法創建一個未映射到磁盤上現有文件的內存映射文件; 適用於為進程間通信(IPC)創建共享內存。

內存映射文件與名稱相關聯。

您可以創建內存映射文件的多個視圖,包括文件各部分的視圖。 您可以將文件的同一部分映射到多個地址以創建並發內存。 要使兩個視圖保持並發,必須從同一個內存映射文件創建它們。 使用兩個視圖創建同一文件的兩個文件映射不提供並發性。

首先: StringReader從已經在內存中的字符串中讀取。 這意味着您必須完整地加載輸入文件才能從中讀取,這種方法一次性讀取幾個字符的目的; 如果輸入非常大,它也可能是不合需要的,甚至是不可能的。

從文本 (對數據源進行抽象)讀取的類是StreamReader ,您可能希望使用該類。 現在, StreamReaderStringReader共享一個抽象基類TextReader ,這意味着如果您針對TextReader進行編碼,那么您可以充分利用這兩個世界。

TextReader的公共接口確實會支持你的示例代碼,所以我認為這是一個合理的起點。 你只需要修復一個明顯的錯誤:沒有檢查Read returns -1(表示可用數據的結束)。

如果你想通過分割字符串來讀取它 - 例如行太長,所以你可能會遇到OutOfMemoryException,你應該這樣做(使用streamreader):

while (sr.Peek() >= 0)
{
    c = (char)sr.Read();
    if (c.Equals(' ') || c.Equals('\t') || c.Equals('\n') || c.Equals('\r'))
    {
        break;
    }
    else
        word += c;
}
return word;

所有在一行中,你去(假設ASCII,也許不是2GB文件):

var file = File.ReadAllText(@"C:\myfile.txt", Encoding.ASCII).Split(new[] { ' ' });

這將返回一個字符串數組,您可以迭代它並執行您需要的任何操作。

我根據您提到的文件創建了一個簡單的控制台程序,它應該很容易運行和檢查。 請查找隨附的代碼。 希望這可以幫助

static void Main(string[] args)
    {

        string[] input = File.ReadAllLines(@"C:\Users\achikhale\Desktop\file.txt");
        string[] array1File = File.ReadAllLines(@"C:\Users\achikhale\Desktop\array1.txt");
        string[] array2File = File.ReadAllLines(@"C:\Users\achikhale\Desktop\array2.txt");

        List<string> finalResultarray1File = new List<string>();
        List<string> finalResultarray2File = new List<string>();

        foreach (string inputstring in input)
        {
            string[] wordTemps = inputstring.Split(' ');//  .Split(' ');

            foreach (string array1Filestring in array1File)
            {
                string[] word1Temps = array1Filestring.Split(' ');

                var result = word1Temps.Where(y => !string.IsNullOrEmpty(y) && wordTemps.Contains(y)).ToList();

                if (result.Count > 0)
                {
                    finalResultarray1File.AddRange(result);
                }

            }

        }

        foreach (string inputstring in input)
        {
            string[] wordTemps = inputstring.Split(' ');//  .Split(' ');

            foreach (string array2Filestring in array2File)
            {
                string[] word1Temps = array2Filestring.Split(' ');

                var result = word1Temps.Where(y => !string.IsNullOrEmpty(y) && wordTemps.Contains(y)).ToList();

                if (result.Count > 0)
                {
                    finalResultarray2File.AddRange(result);
                }

            }

        }

        if (finalResultarray1File.Count > 0)
        {
            Console.WriteLine("file array1.txt contians words: {0}", string.Join(";", finalResultarray1File));
        }

        if (finalResultarray2File.Count > 0)
        {
            Console.WriteLine("file array2.txt contians words: {0}", string.Join(";", finalResultarray2File));
        }

        Console.ReadLine();

    }
}

此代碼將根據Regex模式從文本文件中提取單詞。 您可以嘗試使用其他模式來查看最適合您的模式。

    StreamReader reader =  new StreamReader(fileName);

    var pattern = new Regex(
              @"( [^\W_\d]              # starting with a letter
                                        # followed by a run of either...
                  ( [^\W_\d] |          #   more letters or
                    [-'\d](?=[^\W_\d])  #   ', -, or digit followed by a letter
                  )*
                  [^\W_\d]              # and finishing with a letter
                )",
              RegexOptions.IgnorePatternWhitespace);

    string input = reader.ReadToEnd();

    foreach (Match m in pattern.Matches(input))
        Console.WriteLine("{0}", m.Groups[1].Value);

    reader.Close();       

這是分割你的單詞的方法,當它們被空格或超過1個空格(例如兩個空格)分開時

StreamReader streamReader = new StreamReader(filePath); //get the file
string stringWithMultipleSpaces= streamReader.ReadToEnd(); //load file to string
streamReader.Close();

Regex r = new Regex(" +"); //specify delimiter (spaces)
string [] words = r.Split(stringWithMultipleSpaces); //(convert string to array of words)

foreach (String W in words)
{
   MessageBox.Show(W);
}

我會做這樣的事情:

IEnumerable<string> ReadWords(StreamReader reader)
{
    string line;
    while((line = reader.ReadLine())!=null)
    {
        foreach(string word in line.Split(new [1] {' '}, StringSplitOptions.RemoveEmptyEntries))
        {
            yield return word;
        }
    }
}

如果要使用reader.ReadAllText,它會將整個文件加載到您的內存中,這樣您就可以獲得OutOfMemoryException和許多其他問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM