【问题标题】:StreamWriter even with AutoFlush true leaves lines half written即使使用 AutoFlush true,StreamWriter 也会将行写一半
【发布时间】:2014-05-09 06:29:33
【问题描述】:

我有一个带有 AutoFlush = true 属性的 StreamWriter。但是,当我随机打开它时,我仍然看到该文件仅部分写入。我正在编写一个需要在任何给定时间内完全写入 (JSON) 的文件。

        var sw = new StreamWriter("C:\file.txt", true /* append */, Encoding.ASCII) { AutoFlush = true };
        sw.WriteLine("....");

        // long running (think like a logging application) -- 1000s of seconds

        sw.Close();

在 sw.WriteLine() 调用和 sw.Close() 之间,我想打开文件,并且始终保持“正确的数据格式”,即我的行应该是完整的。

当前想法:

将 FileStream(和/或 StreamWriter)的内部缓冲区增加到 128KB。然后每 128KB-1 调用 FileStream 对象上的 .Flush() 。这引出了我的下一个问题,当我调用 Flush() 时,我是否应该在调用它之前获取 Stream.Position 并执行 File.Lock(Position, 128KB-1)?还是 Flush 会解决这个问题?

基本上我不希望读者能够阅读 Flush() 之间的内容,因为它可能会部分损坏。

【问题讨论】:

  • 如果你使用NTFS并且不关心Windows XP,你可以尝试使用事务-How do I open a Windows 7 transacted file in C#。或者您可以创建一个文件副本,在其中写入内容,然后通过移动操作覆盖原始文件。
  • 如果你显式调用 Flush() 呢?

标签: c# streamwriter


【解决方案1】:
using (StreamWriter sw = new StreamWriter("FILEPATH"))
{
  sw.WriteLine("contents");
  // if you open the file now, you may see partially written lines
  // since the sw is still working on it.
}

// access the file now, since the stream writer has been properly closed and disposed.

【讨论】:

  • 文档不是这么说的
  • (如果你使用 AutoFlush = true)
【解决方案2】:

如果您需要一个永远不会写一半的“类似日志”的文件,那么最好的办法就是不要让它保持打开状态。

每次你想写你的文件,你应该实例化一个新的 FileWriter,它会在释放文件时刷新文件内容,如下所示:

private void LogLikeWrite(string filePath, string contents)
{
  using (StreamWriter streamWriter = new StreamWriter(filePath, true)) // the true will make you append to the file instead of overwriting its contents
  {
    streamWriter.Write(contents);
  }
}

这样你的写操作会被立即刷新。

【讨论】:

  • 我觉得这很难相信。如果是真的(关闭是刷新的唯一方法)那么AutoFlushFlush() 的存在就没有意义了。
  • @WumpusQ.Wumbley 如果您查看MSDN on the topic,您会发现在某些情况下调用.Flush() 或使用.AutoFlush 不会导致预期的行为。这就是为什么推荐使用这基本上是四十多年的行业标准的日志记录方法。
  • 仅仅 2.5 年,我一直在使用 C,从来不用担心 fflush 没有做它应该做的事情(也有行缓冲模式作为选项) ,并不断关闭和重新打开文件以确保它被刷新会被嘲笑。只有在微软世界中,这种丑陋的解决方法才能成为“行业标准”
  • @WumpusQ.Wumbley 您是否知道行缓冲实际上会关闭并重新打开文件流?
  • 如果它是类似日志的,为什么不只是File.AppendAllText(filePath, contents)?你的函数比内置函数有什么优势吗?
【解决方案3】:

如果您在进程之间共享文件,除非您产生某种锁定机制,否则您将遇到竞争条件。见https://stackoverflow.com/a/29127380/892327。这确实要求您能够修改这两个进程。

另一种方法是让进程 A 在指定位置等待文件。进程 B 写入一个中间文件,一旦 B 刷新,文件就会复制到进程 A 期望文件的位置,以便它可以使用该文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    相关资源
    最近更新 更多