2012-03-16 84 views
4

我有一個文本文件,其中只包含小寫字母,沒有空格標點符號。我想知道通過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循環,直到文件的末尾。這種方法是否有意義,或者有更好的方法來實現這一點?

+1

請不要在「C#:」等前加上標題。這就是標籤的用途。 – 2012-03-16 16:03:03

+1

我認爲你應該從文件中讀取更大的塊(比如說4096字節),否則看起來很好......另外,我想知道什麼是最佳尺寸:) – neeKo 2012-03-16 16:05:01

+1

構建這樣的字符串會產生很多對象(記住字符串是不可變的)。如果您想要在讀取文件時建立字符串,請使用'StringBUilder'。 – 2012-03-16 16:05:20

回答

16

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

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

words數組現在包含所有的單詞該文件,你可以做任何你想要的東西。

此外,您可能需要調查System.IO名稱空間中的File.ReadAllText方法 - 它可能會使您的文本導入文件的過程變得更容易。

編輯:我想這假設你的文件不是可惡的大;只要整個事物可以合理地讀入記憶中,這將最容易工作。如果你有千兆字節的數據讀入,你可能會想避開這個。如果可能的話,我會建議使用這種方法:它可以更好地使用您可以使用的框架。

+1

這將最終用於非常大的文本文件,所以這仍然有效嗎? – Matt 2012-03-16 16:07:34

+0

我們說多少? – eouw0o83hf 2012-03-16 16:08:32

+0

方便,當然。 「框架的最大使用」,嗯,真的,沒有。 – Jon 2012-03-16 16:10:39

2

首先:StringReader從已經在內存中的字符串讀取。這意味着你將不得不加載輸入文件的全部內容,然後才能夠讀取它,這種方式會挫敗一次讀取幾個字符的目的;如果輸入非常大,它也可能是不可取的或者甚至是不可能的。

要從文本中讀取的類(它是對數據源的抽象)是StreamReader,您可能想要使用該類。現在StreamReaderStringReader共享一個抽象基類TextReader,這意味着如果你對TextReader編碼,那麼你可以擁有兩全其美。

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

+0

謝謝你,一個非常豐富的答案。我會研究這些事情,但是由於我提出問題的方式,我必須將eouw0o83hf的答案標記爲已接受,並且我認爲這對於其他遇到類似問題的人會更有幫助。再次感謝:) – Matt 2012-03-16 16:24:02

1

所有在同一行,在這裏你去(假設ASCII也許並不是一個2GB的文件):

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

這將返回一個字符串數組,你可以遍歷,做任何你需要。

+2

'.Split('')' - 無需創建數組 – eouw0o83hf 2012-03-16 16:09:11

+1

@ eouw0o83hf:它編譯爲相同的IL,因此無關緊要。 – 2012-03-16 16:13:28

0

這個方法會分裂你的話,而他們之間用空格或超過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); 
} 
0

我會做這樣的事情:

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和其他許多問題。

6

如果您對即使在非常大的文件上也有良好的性能感興趣,您應該查看新的(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)創建共享內存。

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

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

+0

我會檢查出來,謝謝你的幫助:) – Matt 2012-03-16 16:30:30

1

如果你想讀它whitout劈裂字符串 - 例如線太長,所以你可能會遇到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; 
0

我創建一個簡單的控制檯程序,根據您提及的文件確切的要求,應該很容易運行和檢查。請查找附上的代碼。希望這有幫助

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(); 

    } 
} 
0

此代碼將從基於正則表達式模式的文本文件中提取單詞。您可以嘗試使用其他模式來查看最適合您的模式。

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();