【问题标题】:C# Parsing files that are missing new line character at the end of the fileC#解析文件末尾缺少换行符的文件
【发布时间】:2019-07-05 12:37:24
【问题描述】:

问题:解析文件末尾缺少换行符的文件的最佳方法是什么?我应该尝试一下并抓住 OutOfMemoryException 吗?或者,有没有更好的方法?

背景:我正在使用 StreamReader 的 Readline() 方法解析日志文件以读取下一行。因此,基本的循环结构如下所示:

while ((line = sr.ReadLine()) != null)
{
      // Parse the file
}

这很好用,即使是大文件(即 > 2GB)。但是,当下一行不为 null 并且 不包含换行符时,StreamReader 只会读取空格,直到耗尽所有内存并抛出 OutOfMemoryException。这是处理文件末尾缺少的换行符的最佳方法吗?或者,有没有更好的方法来处理这个问题?

注意:文件是从 IIS Exchange Server 创建的。如果没有深入了解我们的 IT 团队,该文件似乎在创建过程中被截断,导致最后一行因为缺少数据而出错。

研究:我在 SO(见下文)上发现了一篇关于使用 File.ReadFile 的帖子。虽然它适用于缺少换行符的小得多的文件(即 2GB)。

https://stackoverflow.com/a/13416225

https://docs.microsoft.com/en-us/dotnet/api/system.io.file.readlines?redirectedfrom=MSDN&view=netframework-4.7.2#System_IO_File_ReadLines_System_String_

编辑

编译器停在下面代码示例中的 While 行。问题不在于代码,而在于文件。我无法发布我们的日志文件。但是,为了演示,在 NotePad++ 中创建几行数据。对于文件的最后一行,删除换行符,然后运行文件。 StreamReader 将在最后一行爆炸,因为它找不到行尾。

以下是删除了所有数据内容的日志文件副本,时间戳和每行末尾的换行符除外。对于最后一行,我包含了数据中断之前的最后一个数据元素(端口号)。注意到最后一行缺少换行符了吗?

【问题讨论】:

  • Note: the file is being created from IIS Exchange Server. 如果生成的文件不正确,我会努力修复那里的错误。
  • 顺便说一句,捕获内存不足的异常是没有用的。到那时,你的记忆力已经不够了——你无能为力。
  • 我无法重现此问题。读取没有尾随 \r\n 的最后一行,然后对 ReadLine() 的下一次调用返回 null。肯定有其他问题。
  • 这不是 StreamReader.ReadLine() 的行为。请发布一个实际的minimal reproducible example 来演示该问题。我可以生成自己的文件,最后缺少 CRLF 进行测试。
  • " StreamReader 将在最后一行爆炸,因为它找不到行尾"? - 完全错误。 StreamReader 将文件结尾视为字符串结尾。

标签: c# parsing streamreader


【解决方案1】:

我已确认该文件在我们的 IT 团队中不正确。发生的事情是,通过网络到我本地的原始传输过程似乎遇到了问题。我重新传输了文件并成功解析。还有更多的行。让我失望的是网络和本地之间的文件大小是相同的——所以我在研究过程中没有考虑重新传输文件。

文件传输过程似乎首先将一个完整的文件分配为空文件,然后开始用数据填充它。祝您好运诊断标准文本编辑器(例如,记事本、Notepadd++、Excel 等)无法打开的超大文件以查看此内容。我不得不使用 Ultra Edit,问题就显现出来了。

根据 Hans Passant 对相关问题的评论(请参阅下面的链接),StreamReader 的 Readline() 方法可以很好地处理大文件,因为它在内部处理文件系统缓存。因此,OutOfMemoryExceptions 应该不是问题。我认为这是针对内存不足而不是坏文件的计算机。

感谢大家的故障排除,对于任何干扰,我深表歉意。

Unable to read large log file with MemoryMappedViewStream

【讨论】:

    【解决方案2】:

    这应该有效: 在尝试读取下一行之前应该检查 EndOfStream 。 还添加了一些对 null 的检查。

    while (!sr.EndOfStream)
    {
      line = sr.ReadLine()?.Trim() ?? "";
      // Parse the line
    }
    

    【讨论】:

    • 感谢您的帖子。我尝试了上面的实现。不幸的是,这不起作用 - 我仍然收到 OutOfMemoryException 错误。还有其他想法或想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 2016-02-02
    • 2013-04-28
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    相关资源
    最近更新 更多