2010-11-25 18 views
53

私は1行ずつ読む必要がある1 GBのテキストファイルを持っています。これを行う最善の方法と最速の方法は何ですか? FormatData().NETで大きな(1 GB)txtファイルを読み取る方法は?

private void ReadTxtFile() 
{    
    string filePath = string.Empty; 
    filePath = openFileDialog1.FileName; 
    if (string.IsNullOrEmpty(filePath)) 
    { 
     using (StreamReader sr = new StreamReader(filePath)) 
     { 
      String line; 
      while ((line = sr.ReadLine()) != null) 
      { 
       FormatData(line);       
      } 
     } 
    } 
} 

私は単語と一致し、そのインクリメント整数変数に基づいていなければならない行の先頭ワードをチェックします。

void FormatData(string line) 
{ 
    if (line.StartWith(word)) 
    { 
     globalIntVariable++; 
    } 
} 
+0

を所有していた会社のために働きますか単純化されたバージョン)。 –

+0

@Matthew:FormatData()を無視するだけで、実際にはプロセス全体が遅いので、トラブルシューティングのためコメントしています。 –

+0

高速なソリューションが必要な場合は、FormatDataを無視することはできません。データを読み込むスレッドとは別のスレッドでデータをフォーマットするのが最適です。 – cspolton

答えて

40

、このシナリオのために設計されたクラスですMemoryMappedFileを試してみてください。

これ以外の場合はStreamReader.ReadLineを使用できます。

+42

シーケンシャルな読み込みだけをしているのであれば、MemoryMappedFileよりもStreamReaderを使うほうがはるかに高速です。ランダムマッピングの方がメモリマッピングが優れています。 – Homde

+3

さらに、1Gb全体にまたがるViewAccesorを作成することはできないため、これを管理して改行を解析する必要があります。 FileStreamは、シーケンシャル読み取りのためにMemory-Mappedファイルの10倍高速です。 – Homde

+2

@ konrad - 合意された素晴らしいコメントです。これについては、O'Reillyの優れた「C#4.0 in a Nutshell」(569ページ)を参照してください。シーケンシャルI/Oと1GBのファイルサイズの場合、MemoryMappedFilesは間違いありません過度のことを遅らせるかもしれません。 –

9

Probably to read it line by line.

あなたはむしろ最後まで読んで、その後の処理によってメモリにそれを強制しようとするべきではありません。

6

StreamReader.ReadLineは正常に動作するはずです。あなたがプロファイリングによってあなたがより良くできることがわからない限り、フレームワークにバッファリングを選択させてください。あなたは.NET 4.0を使用している場合

+0

StreamReader.ReadLineは小さなファイルでは問題ありませんが、大きなファイルで試してみると、応答がないときは非常に遅いです。 –

+0

@Jeevan、あなたのコードを投稿してください。また、典型的な線はどのくらいの長さですか? –

+0

@Mathew:投稿コードを見て、行の長さはいくつかの時間行がわずか200ワードとそれは2000以上になるいくつかの時間が含まれて修正されていません。 –

28

おそらくStreamReaderを使用するのは、ファイル全体を一度にメモリに入れたくないからです。 MemoryMappedFileは、シーケンシャルリード(シーケンシャルリードの場合は10倍、ランダムアクセスの場合はメモリマッピングが10倍高速)よりもランダムアクセスの方が多くなります。 (FileOptions Enumeration参照)

はまたSequentialScanに設定FileOptionsはしてFILESTREAMからあなたのStreamReaderを作成してみてくださいかもしれないが、私はそれが大きな違いを行います疑います。

ただし、読んだものと同じループで書式を設定するので、例をもっと効果的にする方法はあります。あなたはクロックサイクルを浪費しています。したがって、パフォーマンスをさらに向上させるには、あるスレッドがデータを読み込み、別のスレッドが使用可能になるようにフォーマットする、マルチスレッド非同期ソリューションを使用する方が良いでしょう。あなたのニーズに合うかもしれませんチェックアウトBlockingColletion:

Blocking Collection and the Producer-Consumer Problem

あなたが最速のパフォーマンスをしたい場合は、私の経験では唯一の方法は、大規模としてバイナリデータを順次のチャンクを読み込むと、テキストにそれをデシリアライズすることです同時に、コードはその時点で複雑になり始める。

+1

+1制限要因はディスクからの読み込み速度になるため、パフォーマンスを向上させるために、スレッドの読み込みと行の処理の違いがあります。 – cspolton

0

一度に10,000バイトのファイルを読み込みました。それから私はそれらの10,000バイトを分析して、それらをラインに切り詰め、それらをFormatData関数に送ります。

複数のスレッドで読み取りとラインの解析を分割するためのボーナスポイント。

私は確かにすべての文字列を収集するためにStringBuilderを使用し、メモリ内に常に約100文字列を保持するために文字列バッファを構築することができます。

14

あなたはLINQを使用することができます。

int result = File.ReadLines(filePath).Count(line => line.StartsWith(word)); 

File.ReadLinesが遅延し、メモリにファイル全体をロードせずに、ファイルから各行を読み込みIEnumerable<String>を返します。

Enumerable.Countは、単語で始まる行をカウントします。

UIスレッドから呼び出す場合は、BackgroundWorkerを使用します。

1

大きなファイル(時には10-25ギガバイト(\ t)のタブ区切りのtxtファイル)が表示されるAgentyのプロダクションサーバーで同じ問題が発生しました。多くのテストと研究の後、私は大規模なファイルを小さな塊で/ foreachループで読み込み、File.ReadLines()でオフセットとリミットロジックを設定する最も良い方法を見つけました。

int TotalRows = File.ReadLines(Path).Count(); // Count the number of rows in file with lazy load 
int Limit = 100000; // 100000 rows per batch 
for (int Offset = 0; Offset < TotalRows; Offset += Limit) 
{ 
    var table = Path.FileToTable(heading: true, delimiter: '\t', offset : Offset, limit: Limit); 

// Do all your processing here and with limit and offset and save to drive in append mode 
// The append mode will write the output in same file for each processed batch. 

    table.TableToFile(@"C:\output.txt"); 
} 

は私のGithubのライブラリに完全なコードを参照してください:https://github.com/Agenty/FileReader/

完全な開示 - 私は(Agenty、このライブラリとウェブサイト

あなたは `FormatData`を投稿することができます
関連する問題