【问题标题】:coroutine/reactive extensions - write lines协程/反应式扩展 - 写行
【发布时间】:2014-09-03 13:53:33
【问题描述】:

我正在使用这两个函数来读取和写入大文件(写入多个文件)。我想将文件操作保留在函数中,因为这些行可能是从其他来源读/写的。

更新: C# 并没有真正的协程。这是响应式扩展的好用例吗?

foreach (var line in ReadFrom("filename"))
{
    try 
    {
        .... // Some actions based on the line
        var l = ..... 
        WriteTo("generatedFile1", l);
    }
    catch (Exception e)
    {
        var l = ..... // get some data from line, e and other objects etc.
        WriteTo("generatedFile2", l);
    }
}

以下函数打开文件一次,直到读取所有行,然后关闭并释放资源。

    private static IEnumerable<string> ReadFrom(string file)
    {
        string line;
        using (var reader = File.OpenText(file))
        {
            while ((line = reader.ReadLine()) != null)
                yield return line;
        }
    }

但是,以下函数写入行而不是读取行,它会为它写入的每一行打开和关闭文件。是否有可能以某种方式实现它,使其只打开一次文件并继续写入文件,直到发送 EOF?

    private static void WriteTo(string file, string line)
    {
        if (!File.Exists(file)) // Remove and recreate the file if existing
            using (var tw = File.CreateText(file))
            {
                tw.WriteLine(line);
            }
        else
            using (var tw = new StreamWriter(file, true))
            {
                tw.WriteLine(line);
            }
    }

【问题讨论】:

  • 你的第一种方法可以用File.ReadLines代替,第二种方法可以用File.WriteLines代替
  • 是否要求您一次处理一行(例如非常大的文件)?否则,File.ReadAllLines 很好。
  • @SriramSakthivel:您只需要注意不要使用File.WriteAllLines("path",File.ReadLines("path")),它会尝试写入您当前正在阅读的文件。
  • @WeSt 在我看来,您基本上不应该使用File.ReadAllLines。这是一种过时的方法。您实际上应该始终使用File.ReadLines。 OP 在此处的方法旨在做几乎相同的事情,只是它没有 File.ReadLines 中的错误。
  • @Servy:过于笼统,例如,如果您想修改现有文件,您不能在不将其读入内存的情况下使用File.ReadLines。您也不能再次使用它(例如var lines=File.ReadLines(..); string header=lines.First(); 如果您现在尝试再次使用lines,您将看到ObjectDisposedException

标签: c# .net system.reactive coroutine


【解决方案1】:

只需使用File.WriteAllLines。它将按顺序将所有行写入文件,并且不会为每一行打开/关闭文件。

【讨论】:

  • 行数是代码生成的,可能有几百万行。
  • @dc7a9163d9 好的。没关系。此方法将从序列中单独读取行并将它们写出,而不会将整个内容缓冲到内存中。如果你愿意,你可以拥有数十亿行。
  • 也许让主循环成为一个函数 yield 返回IEnumerable&lt;string&gt; 并将其传递给File.WriteAllLines
  • @dc7a9163d9 这是一个选项,但您可能不需要这样做。如果您的输入是从另一个文件读入的,那么您已经有一种方法可以从一个文件流式传输数据,您可以在使用 LINQ 流式传输数据时简单地操作数据,并将数据写入另一端的另一个文件你的管道。
  • File.WriteAllLines() 不接受IEnumerable&lt;string&gt; 并且需要使用ToList()ToArray 进行转换,这将在内存中创建一个副本?见stackoverflow.com/questions/6394165/…
【解决方案2】:

您可以删除整个第二种方法,并将调用替换为var writer = new StreamWriter(file, true),如that constructor creates the file if it does not exist

然后你可以使用writer.WriteLine()直到你写完,然后再使用Dispose()

【讨论】:

  • 但他并不关心创建文件。他不想为了写一行而反复打开和关闭它。
  • 我要说的是这是一种无用的方法,并且可以通过按照我在回答中所说的来解决OP的问题。如果这不能回答他的问题,OP 应该提供更多上下文(例如“我不想保留参考”)。 OP 不想为他写的每一行打开和关闭文件,那么他应该在某处保留对作者的引用(见:我的答案)或一次写所有行(见:@Servy 的答案)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2011-08-27
  • 2012-01-15
相关资源
最近更新 更多