【问题标题】:How to ensure that StreamReader.BaseStream.Length will return the correct value?如何确保 StreamReader.BaseStream.Length 将返回正确的值?
【发布时间】:2016-01-18 21:45:29
【问题描述】:

我有一个循环将BaseStream.LengthlastMaxOffset 进行比较,假设10 次中有9 次运行正常。
但这是 BaseStream.Length 以某种方式设置为 0 的 1 次 - 在调试模式下它显示正常值,始终大于 0 - 这导致我的控制台应用程序出现问题。 我验证了长度不等于 0,因为它是一个只会增长的日志文件。所以我猜这是一个 BaseStream 问题(可能暂时没有长度值,所以将其设置为 0) 有没有办法确保StreamReader.BaseStream.Length 只返回正确的值?

using (StreamReader reader = new StreamReader(
    new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), 
    Encoding.Default))
{
    long lastMaxOffset = this.getMaxOffsetForFile(path);
    if ( lastMaxOffset == 0 )
    {
        lastMaxOffset = this.setMaxOffsetForFile(path, reader.BaseStream.Length);
    }

    reader.DiscardBufferedData();
    long fileLength = reader.BaseStream.Length;

    if (fileLength > lastMaxOffset)
    { 
         //my code 
    }
}

【问题讨论】:

  • @CodeCaster 我已经看过这篇文章,实际上我在我的代码阅读器上添加了。DiscardBufferedData();因为flush是针对StreamWriter的,但是还是会报错。
  • 然后修复您的问题中的StreamWriter。无论如何,阅读器也会缓冲。
  • 我认为StreamReader.BaseStream属性是框架中的设计错误。这根本不应该暴露。
  • @usr 你能建议一种方法来确保我能得到正确的值吗?正如我所说,不能正常运行的情况很少见,但我应该排除这种可能的错误

标签: c# streamreader content-length


【解决方案1】:

您正在读取一个正在被另一个进程写入的文件。 FileShare.ReadWrite 为您提供了执行此操作的后门。该过程没有义务让您的生活变得轻松。

您正在使用 FileStream.Length,它没有任何问题。除了使用 GetFileSize() 向操作系统询问文件大小外,它什么也不做。您总是可以假设某种有缺陷的网络文件系统,但这永远不会让您到达任何地方。这里的正确假设是您实际上看到了这个过程的作用。

它有时会截断文件。发生这种情况时,您将得到 0。或者其他一些小的数字,它不必为 0,而且当您在进程继续写入文件时进行调试时,它当然不必重复。

日志文件没有什么不寻常的,它们不会永远增长。您必须编写代码来适应这种情况。很难做到 100% 正确,您不能依赖可靠的 Length 值。当您获得一个小于前一个值的新值时,唯一合理的做法是假设进程开始重写日志文件,因此您必须再次开始读取偏移量 0(不是 Length 也不是 lastMaxOffset)。强烈建议使用电话与此应用程序的程序员交谈以验证这些假设。

【讨论】:

  • 感谢您的评论。我已经有一个 if else 正在检查 if (fileLength
  • 嗯,不,这是答案,不是评论。它解释了为什么得到 0 是正常的。这可能会对您的代码产生令人不快的副作用,例如无法正确刷新您自己的缓冲日志数据,这是理所当然的。您的 sn-p 不足以诊断原因。如果您不想使用电话,那么接下来最好的做法是编写您自己的测试应用程序,记录这样的日志,故意使用 FileStream.SetLength() 截断命令中的文件以触发问题场景。
  • 好吧,我明白你的意思了……!这很有帮助。我添加了对文件创建日期的检查,现在错误没有发生。再次感谢您的帮助
  • 为了将来参考,我注意到即使暂停程序一小段时间也不会出现错误。我添加了以下行 System.Threading.Thread.Sleep(20);并且错误没有再次发生。
猜你喜欢
  • 2022-01-19
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多