【问题标题】:How to Read from and then Write/Append to a Text File without re-opening the file?如何在不重新打开文件的情况下读取然后写入/追加到文本文件?
【发布时间】:2015-02-25 20:25:43
【问题描述】:

如何打开 FileStream,读取文件内容,然后写入(追加)到文件而不重新打开文件?

在这种情况下,StreamReader/StreamWriter 的问题是they assume ownwership of the underlying stream。由于目标是 .NET 4,因此无法使用 "leaveOpen" constructor overloads。 (我不在乎是否使用了 StreamReader/StreamWriter - 但它们确实提供了 ReadLine 和 WriteLine 操作。)

总之,与问题相关的问题代码示例以及应用程序如何访问和管理 FileStream 的生命周期(即打开一次):

var fs = File.Open(..);
using (var reader = new StreamReader(fs)) {
   // Do all reading here, then ditch the reader
}  // .. but StreamReader will Close the FileStream

SeekToEnd(fs);

using (var writer = new StreamWriter(fs)) {
   // Do all writing here, then ditch the writer
   // .. ideal, but FileStream already Closed
}

// Finally, somewhere else:
fs.Close();

我发现的“相关”MSDN 文章总是将其显示为两个单独的步骤:这个问题是关于以面向行的方式执行 Text 的读写操作无需两次打开文件。

文件打开方式为

File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite)

并且底层流将始终是可查找和可写的。

【问题讨论】:

  • 为什么必须先关闭阅读器才能打开编写器?为什么不能同时打开它们?
  • @gunr2171 “长时间运行的应用程序”。第一阶段是重播日志,第二阶段是附加到同一个日志。虽然我可以无限期地保留阅读器,这样它就永远不会关闭,我真的很想找到一个“更好”的方法。
  • 我认为关于流阅读器最重的事情是实际的流,我不认为只让它们都打开有什么害处,在你的情况下解决这个问题的唯一其他方法是实施不处理文件流的新流读取器和写入器
  • 这不是关于“使用资源”(毕竟只有一个 FileStream,并且阅读器使用的整个缓冲区无关紧要) - 这是关于使用字段“摇头”只是为了维护读取器生命周期(必须保持 GC-alive)并在读取周围使用 using 省略(这是本地操作,写入将发生多次,直到父级被释放)。
  • @user2864740 我知道你想这样做(因为这样更有意义)但你要么必须自己实现它,要么只保持变量打开,或者升级到一个版本.NET 允许您使用您提到的标志来保持文件流打开

标签: c# .net .net-4.0 filestream streamreader


【解决方案1】:

您可以将流的位置设置为流的末尾并从那里写入

 fs.Position = fs.Length;
 //then do the write operations you need to do

即使您使用的是流式写入器或读取器,您也应该能够修改读取器/写入器正在使用的 FileStream,这样您就可以先读取再写入

using(var fs = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite)
{
    using(var reader = new TextReader(fs))
    using(var writer = new TextWriter(fs))
    {
        //read

        fs.Position = fs.Length;

        //write
    }
}

【讨论】:

  • FileStream 不提供来自 StreamReader/StreamWriter 的与文本相关的操作方法,例如 WriteLine 和 ReadLine - 当 StreamReader/StreamWriter 被 Disposed 时,它将(默认情况下)自动释放底层流。我仅限于 .NET 4,所以我 cannot use the "leaveOpen" constructor overloads.
  • @user2864740,更新了答案,即使流被阅读器使用,您仍然应该能够修改流,如果是这种情况,请等到最后处理两个流处理对象
  • 虽然在 读者被处置后(事实上 Dispose 调用是幂等的),该更新“会起作用”,但它回避了这个问题。我不想让读者“只是为了不关闭源”(它也必须保持 GC-alive)。在这个应用程序中,读取在开始时完成一次,并在一段时间内完成写入,直到应用程序关闭(将其视为日志)。
  • @user2864740:您是否担心保持 TextReader 未处理会导致某种性能问题?我怀疑保持 TextReader 打开的内存成本是微不足道的,考虑到您仍然希望底层流保持打开状态。
  • @StriplingWarrior 不,我不担心“性能”——我是 97/3。我也遵循 3(或 6)种美德。请参阅我对主要问题的评论。
猜你喜欢
  • 2021-09-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 2013-12-26
  • 2010-11-04
相关资源
最近更新 更多