【问题标题】:C# Reading StreamC# 阅读流
【发布时间】:2013-08-14 13:59:14
【问题描述】:

我想在 C# 中读取一个 .txt 文件,但我不会同时读取所有行。例如,考虑 500 行文本文件。我想要一个函数运行 25 次,每次读取 20 行连续的行。函数第一次调用会读取1到20行,第二次调用会读取21-40行。

下面的简单代码在 c++ 中执行此操作,但我不知道如何在 C# 中实现它:

string readLines(ifstream& i)
{
     string totalLine="", line = "";
     for(int i = 0; i < 20; i++){
          getline(i, line);

          totalLine += line;
     }
     return totalLine;
}

int main()
{

     // ...
     ifstream in;
     in.open(filename.c_str());
     while(true){
         string next20 = readLines(in);
         // so something with 20 lines.
     }
     // ...

}

【问题讨论】:

  • 您在 C++ 中给出的代码根本不这样做 - 它只是循环读取 all 行。这在 C# 中也很容易做到……foreach (string line in File.ReadLines(...))。批处理在 C# 中还不错...
  • 这只是一个简单的例子。我的意思是,如果你将 while 语句放入一个函数中,即使你过早地退出读取文件,它也会从中断的地方继续。
  • @MertToka:那个“快速示例”并没有说明你当时想要做什么——它基本上没有给问题添加任何东西。
  • @JonSkeet 请查看编辑。

标签: c# file-io filestream


【解决方案1】:

这里有多种选择,但一种简单的方法是:

using (var reader = File.OpenText("file.txt"))
{
    for (int i = 0; i < 25; i++)
    {
        HandleLines(reader);
    }
}

...

private void HandleLines(TextReader reader)
{
    for (int i = 0; i < 20; i++)
    {
        string line = reader.ReadLine();
        if (line != null) // Handle the file ending early
        {
            // Process the line
        }
    }
}

【讨论】:

    【解决方案2】:

    如果尝试以尽可能少的次数调用LineRead(),并且您希望最小内存使用量,您可以首先索引文件中的行:

    1. 解析文件一次并索引每一行在FileStream中的位置。
    2. 仅在所需位置调用 ReadLine()

    例如:

    // Parse the file
    var indexes = new List<long>();
    using (var fs = File.OpenRead("text.txt"))
    {
        indexes.Add(fs.Position);
        int chr;
        while ((chr = fs.ReadByte()) != -1)
        {
            if (chr == '\n')
            {                        
                indexes.Add(fs.Position);
            }
        }
    }
    
    int minLine = 21;
    int maxLine = 40;
    
    // Read the line
    using (var fs = File.OpenRead("text.txt"))
    {
        for(int i = minLine ; i <= maxLine ; i++)
        {
            fs.Position = indexes[ i ];
            using (var sr = new StreamReader(fs))
                Console.WriteLine(sr.ReadLine());
    
    }
    

    干杯!

    【讨论】:

      【解决方案3】:

      你可以像这样写一个 Batch() 方法:

      public static IEnumerable<string> Batch(IEnumerable<string> input, int batchSize)
      {
          int n = 0;
          var block = new StringBuilder();
      
          foreach (var line in input)
          {
              block.AppendLine(line);
      
              if (++n != batchSize)
                  continue;
      
              yield return block.ToString();
              block.Clear();
              n = 0;
          }
      
          if (n != 0)
              yield return block.ToString();
      }
      

      然后这样称呼它:

      string filename = "<Your filename goes here>";
      var batches = Batch(File.ReadLines(filename), 20);
      
      foreach (var block in batches)
      {
          Console.Write(block);
          Console.WriteLine("------------------------");
      }
      

      【讨论】:

        【解决方案4】:

        哎呀。 GroupBy 不会懒惰地评估,所以这会贪婪地消耗整个文件

        罢工>

        var twentyLineGroups = 
            File.ReadLines(somePath)
                .Select((line, index) => new {line, index})
                .GroupBy(x => x.index / 20)
                .Select(g => g.Select(x => x.line));
        
        foreach(IEnumerable<string> twentyLineGroup in twentyLineGroups)
        {
            foreach(string line in twentyLineGroup)
            {
                //tada!
            }
        }
        

        【讨论】:

        • 所以这段代码实际上将行除以 20,然后在遍历组的同时遍历行,对吗?我对第一个语句的功能非常陌生。
        猜你喜欢
        • 2013-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-23
        • 2016-02-14
        • 1970-01-01
        • 2014-07-11
        • 2014-10-31
        相关资源
        最近更新 更多