逐字阅读文本文件

时间:2012-03-16 15:58:34

标签: c#

我有一个文本文件,只包含小写字母,除空格外没有标点符号。我想知道通过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循环中直到文件结束。这种方法是否有意义,或者有更好的方法来实现这一目标吗?

9 个答案:

答案 0 :(得分:17)

有一种更好的方法:string.Split():如果你读完整个字符串,C#可以在每个空间自动拆分它:

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

words数组现在包含文件中的所有单词,您可以随意使用它们。

此外,您可能需要调查File.ReadAllText命名空间中的System.IO方法 - 它可能会让您的文章导入文本变得更加轻松。

编辑:我想这假设您的文件不是很大;只要整个事物可以合理地读入内存,这将最容易。如果你有数千兆字节的数据要读,你可能会想回避这一点。我建议尽可能使用这种方法:它可以更好地利用您拥有的框架。

答案 1 :(得分: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方法从a创建内存映射文件   指定的路径或磁盘上现有文件的FileStream。变化   在取消映射文件时会自动传播到磁盘。

     

CreateNew方法创建未映射的内存映射文件   到磁盘上的现有文件;并适合创建共享   进程间通信(IPC)的内存。

     

内存映射文件与名称相关联。

     

您可以创建内存映射文件的多个视图,包括   文件部分的视图。您可以将文件的相同部分映射到   多个地址来创建并发内存。对于两个视图   保持并发,它们必须从相同的内存映射创建   文件。使用两个视图创建同一文件的两个文件映射   不提供并发性。

答案 2 :(得分:3)

首先:StringReader从已经在内存中的字符串中读取。这意味着您必须完整地加载输入文件才能从中读取,这种方法一次性读取几个字符的目的;如果输入非常大,它也可能是不可取的,甚至是不可能的。

从文本 stream (这是对数据源的抽象)中读取的类是StreamReader,您可能希望使用该类。现在StreamReaderStringReader共享一个抽象基类TextReader,这意味着如果您针对TextReader进行编码,那么您可以充分利用这两个世界。

TextReader的公共接口确实会支持你的示例代码,所以我认为这是一个合理的起点。您只需修复一个明显的错误:没有检查Read返回-1(表示可用数据的结束)。

答案 3 :(得分:1)

所有在一行中,你去(假设ASCII,也许不是2gb文件):

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

这将返回一个字符串数组,您可以迭代它并执行您需要的任何操作。

答案 4 :(得分: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;

答案 5 :(得分: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);
}

答案 6 :(得分: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和许多其他问题。

答案 7 :(得分: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();

    }
}

答案 8 :(得分:0)

此代码将根据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();