【问题标题】:Out-of-memory error while reading very large text file in vb.net在 vb.net 中读取非常大的文本文件时出现内存不足错误
【发布时间】:2013-02-05 17:35:13
【问题描述】:

我的任务是处理一个 3.2GB 的定宽分隔文本文件。每行有 1563 个字符长,文本文件中大约有 210 万行。在阅读了大约 100 万行之后,我的程序因内存不足异常错误而崩溃。

Imports System.IO
Imports Microsoft.VisualBasic.FileIO

Module TestFileCount
    ''' <summary>
    ''' Gets the total number of lines in a text file by reading a line at a time
    ''' </summary>
    ''' <remarks>Crashes when count reaches 1018890</remarks>
    Sub Main()
        Dim inputfile As String = "C:\Split\BIGFILE.txt"
        Dim count As Int32 = 0
        Dim lineoftext As String = ""

        If File.Exists(inputfile) Then
            Dim _read As New StreamReader(inputfile)
            Try
                While (_read.Peek <> -1)
                    lineoftext = _read.ReadLine()
                    count += 1
                End While

                Console.WriteLine("Total Lines in " & inputfile & ": " & count)
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            Finally
                _read.Close()
            End Try
        End If
    End Sub
End Module

这是一个非常简单的程序,一次读取一行文本文件,所以我认为它不应该在缓冲区中占用太多内存。

对于我的生活,我无法弄清楚它为什么会崩溃。这里有人有什么想法吗?

【问题讨论】:

  • 这可能是您的StreamReader 的缓冲区大小吗?您可以在构造函数中更改大小。
  • 另外,你是为 x86 还是 x64 编译这个?
  • 每次都会在完全相同的文件偏移处崩溃吗?如果是这样,请确认预期的换行符确实存在于该位置。
  • 你确定换行符是\n\r吗?在换行方面,您的文本编辑器可能比 StreamReader 更宽容。
  • 为什么要读整行?只需获取每行的第一个字符并添加到您的计数中...?

标签: .net vb.net out-of-memory


【解决方案1】:

我不知道这是否能解决您的问题,但不要使用 peek,将您的循环更改为:(这是 C#,但您应该能够将其转换为 VB)

while (_read.ReadLine() != null)
{
    count += 1
}

如果您需要在循环中使用文本行而不是仅计算行数,只需将代码修改为

while ((lineoftext = _read.ReadLine()) != null)
{
    count += 1
    //Do something with lineoftext
}

有点离题和作弊,如果每行真的是 1563 个字符长(包括行尾)并且文件是纯 ASCII(所以所有字符占用一个字节)你可以这样做(再次 C# 但是你应该会翻译)

long bytesPerLine = 1563;
string inputfile = @"C:\Split\BIGFILE.txt"; //The @ symbol is so we don't have to escape the `\`
long length;

using(FileStream stream = File.Open(inputFile, FileMode.Open)) //This is the C# equivilant of the try/finally to close the stream when done.
{
    length = stream.Length;
}

Console.WriteLine("Total Lines in {0}: {1}", inputfile, (length / bytesPerLine ));

【讨论】:

  • 如果比我有更多 VB 经验的人想要编辑我的代码并“VB-ify”它,请继续。
  • 我试用了您的 Filestream 解决方案,它非常适合获取行数。谢谢!
  • 作为健全性检查,您可以执行if (length Mod bytesPerLine &lt;&gt; 0) then ''do something here to show the error。它的作用是让您知道您的 length / bytesPerLine 操作是否有余数,因为您正在进行整数除法,任何余数都会被截断,您需要使用 Mod 来获取余数。 (例如11 / 4 = 211 Mod 4 = 3)。此运算符的 C# 版本是 %
  • 长度为 3279546588。使用 1593 为 BytesPerLine,总行数为 2098238,余数为 594。
  • 如果每一行的行数都为 1593,则余数应为 1591、1592 或 0(如果最后一行没有 \r\n,如果没有 \n,或者如果最后一行与其他行匹配)。您确定在 1593 计数中包含行尾字符吗?您还确定 EVERY 行是 1593 长吗?
【解决方案2】:

尝试使用ReadAsync,或者你可以使用DiscardBufferedData(但是这个慢)

Dim inputfile As String = "C:\Example\existingfile.txt" 
    Dim result() As String 
    Dim builder As StringBuilder = New StringBuilder()

    Try
        Using reader As StreamReader = File.OpenText(inputfile)
            ReDim result(reader.BaseStream.Length)
            Await reader.ReadAsync(result, 0, reader.BaseStream.Length)
        End Using 

        For Each str As String In result
            builder.Append(str)         
        Next
      Dim count as Integer=builder.Count()
       Console.WriteLine("Total Lines in " & inputfile & ": " & count)
    Catch ex As Exception
            Console.WriteLine(ex.Message)
    End Try

【讨论】:

  • 抱歉 - 我应该提到我正在使用 Visual Studio 2008 和 .NET 3.0。这意味着我不能使用 StreamReader ReadAsync 方法。
猜你喜欢
  • 1970-01-01
  • 2017-10-03
  • 2011-09-18
  • 2015-07-27
  • 2021-04-23
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多