2012-03-16 79 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();