web-dev-qa-db-ja.com

大きな読み取りTXTファイル、メモリ不足の例外

読みたいTXTファイルサイズは500 MB、最初に使用する

var file = new StreamReader(_filePath).ReadToEnd();  
var lines = file.Split(new[] { '\n' });

しかし、それはメモリ例外をスローし、それから私は行ごとに読み込もうとしましたが、約150万行を読んだ後、それはメモリ例外をスローしました

  using (StreamReader r = new StreamReader(_filePath))
         {            
             while ((line = r.ReadLine()) != null)            
                 _lines.Add(line);            
         }

または私が使った

  foreach (var l in File.ReadLines(_filePath))
            {
                _lines.Add(l);
            }

しかし、再び受け取った

タイプ 'System.OutOfMemoryException'の例外がmscorlib.dllで発生しましたが、ユーザーコードでは処理されませんでした

私のマシンは8GBのRAMを備えた強力なマシンなので、マシンの問題ではありません。

ps:NotePadd ++でこのファイルを開こうとしたところ、「ファイルが大きすぎて開けない」という例外が発生しました。

15
Behnam

File.ReadLines を使用するだけで、IEnumerable<string>が返され、一度にすべての行がメモリに読み込まれません。

foreach (var line in File.ReadLines(_filePath))
{
    //Don't put "line" into a list or collection.
    //Just make your processing on it.
}
34
L.B

例外の原因は、_linesコレクションが増えているが大きなファイルを読み取っていないことです。あなたは行とadding to some collection _lines which will be taking memory and causing out of memory execptionを読んでいます。フィルターを適用して、必要な行のみを_linesコレクションに配置できます。

4
Adil

編集:

ファイル全体をメモリにロードすると、オブジェクトが大きくなり、.netがオブジェクトに十分な連続メモリを割り当てられない場合、OOM例外がスローされます。

答えは同じです。コンテンツ全体を読み取るのではなく、ファイルをストリーミングする必要があります。これには、アプリケーションの再設計が必要になる場合がありますが、IEnumerable<>メソッドを使用すると、アプリケーションのさまざまな領域でビジネスプロセスを積み上げて、処理を延期できます。


RAMの8GBの「強力な」マシンは、500が8よりも大きいので、500GBのファイルをメモリに格納できません(さらに、オペレーティングシステムは一部を保持します。Netですべてのメモリを割り当てることはできません。32ビットには2GBの制限があり、ファイルを開いて行を保存するとデータが2回保持されます。オブジェクトサイズのオーバーヘッドがあります。..)

全部をメモリにロードして処理することはできません。処理を通じてファイルをストリーミングする必要があります。

1
cjk

最初に行を数える必要があります。遅いですが、2,147,483,647行まで読み取ることができます。

int intNoOfLines = 0;
using (StreamReader oReader = new 
StreamReader(MyFilePath))
{
    while (oReader.ReadLine() != null) intNoOfLines++;
}
string[] strArrLines = new string[intNoOfLines];
int intIndex = 0;
using (StreamReader oReader = new 
StreamReader(MyFilePath))
{
    string strLine;
    while ((strLine = oReader.ReadLine()) != null)
    {
       strArrLines[intIndex++] = strLine;
    }
}
0