5

私は、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

これは、テキスト ファイルを一度に 1 行ずつ読み取る非常に単純なプログラムなので、バッファ内のメモリをあまり消費しないはずだと思います。

私の人生では、なぜクラッシュするのかわかりません。ここに誰かアイデアがありますか?

4

2 に答える 2

1

これで問題が解決するかどうかはわかりませんが、peek を使用せずに、ループを次のように変更してください (これは C# ですが、VB に変換できるはずです)。

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

行を数えるだけでなく、ループ内でテキスト行を使用する必要がある場合は、コードを次のように変更します。

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

各行が実際に 1563 文字の長さ (行末を含む) であり、ファイルが純粋な ASCII である (つまり、すべての文字が 1 バイトを占める) 場合、ちょっとしたトピックとごまかしのようなものです (もう一度 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 ));
于 2013-02-05T04:12:19.080 に答える
0

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
于 2013-02-05T09:35:13.187 に答える