2

各行に単一の文字列を含むログ ファイルがあります。ファイルから重複データを削除し、ファイルを新しいファイルとして保存しようとしています。最初はデータを HashSet に読み込んでからハッシュセットの内容を保存することを考えていましたが、これを行おうとすると (文字列をハッシュセットに追加する行で) 「OutOfMemory」例外が発生します。

ファイルには約 32,000,000 行あります。比較ごとにファイル全体を再読み込みするのは現実的ではありません。

何か案は?私の他の考えは、コンテンツ全体を SQLite データベースに出力し、DISTINCT 値を選択することでしたが、それが多くの値で機能するかどうかはわかりません。

ご意見ありがとうございます。

4

3 に答える 3

2

を初期化するために配列を使用しようとしましたかHashSet。の倍加アルゴリズムHashSetOutOfMemoryException.

var uniqueLines = new HashSet<string>(File.ReadAllLines(@"C:\Temp\BigFile.log"));

編集

.Add() メソッドの結果をテストして、冗長なアイテムの数をカウントするために false が返されるかどうかを確認しています。できればこの機能は残しておきたい。

HashSet次に、ファイルの行の正しい (最大) サイズで初期化を試みる必要があります。

int lineCount = File.ReadLines(path).Count();
List<string> fooList = new List<String>(lineCount);
var uniqueLines = new HashSet<string>(fooList);
fooList.Clear();
foreach (var line in File.ReadLines(path))
    uniqueLines.Add(line);
于 2012-11-03T18:25:26.887 に答える
2

最初に考える必要があるのは、大量のメモリ消費が問題であるかどうかです。

アプリケーションが常に大量の RAM を使用できるサーバー上で実行される場合、または十分なメモリがあることがわかっている場合は、アプリケーションが低メモリで実行される場合にはできない多くのことを行うことができます。メモリ環境、または未知の環境で。メモリが問題でない場合は、アプリケーションが 64 ビット アプリケーションとして (もちろん、64 ビット OS 上で) 実行されていることを確認してください。国旗)。この場合、これはあなたの問題であり、変更するだけでよいと思います-そして、うまく機能します(十分なメモリがあると仮定します)。

メモリに問題があり、あまり多くのメモリを使用する必要がない場合は、提案したようにすべてのデータをデータベースに追加できます (私は SQL Server のようなデータベースに精通していますが、SQLite で十分だと思います)。列に正しいインデックスを付けてから、個別の値を選択します。

別のオプションは、ファイルをストリームとして 1 行ずつ読み取り、各行についてハッシュを計算し、その行を他のファイルに保存し、ハッシュをメモリに保持することです。ハッシュが既に存在する場合は、次の行に移動します (必要に応じて、削除された行数のカウンターに追加します)。その場合、メモリに保存されるデータは少なくなります (重複していないアイテムのハッシュのみ)。

幸運を祈ります。

于 2012-11-03T18:28:16.633 に答える
1

私は HashSet を使用して Tim に同様のアプローチを取りました。手動の行カウントと比較を追加しました。

サイズが 58MB、312248 行の Windows 8 インストールからセットアップ ログを読み取り、LinqPad で .993 秒で実行しました。

var temp=new List<string>(10000);
var uniqueHash=new HashSet<int>();
int lineCount=0;
int uniqueLineCount=0;

using(var fs=new FileStream(@"C:\windows\panther\setupact.log",FileMode.Open,FileAccess.Read))
    using(var sr=new StreamReader(fs,true)){
        while(!sr.EndOfStream){
        lineCount++;
        var line=sr.ReadLine();
        var key=line.GetHashCode();
            if(!uniqueHash.Contains(key) ){
                uniqueHash.Add(key);
                temp.Add(line);
                uniqueLineCount++;
                    if(temp.Count()>10000){
                        File.AppendAllLines(@"c:\temp\output.txt",temp);
                        temp.Clear();
                    }
            }
        }
    }
Console.WriteLine("Total Lines:"+lineCount.ToString());
Console.WriteLine("Lines Removed:"+ (lineCount-uniqueLineCount).ToString());

linqpad のパフォーマンス

于 2012-11-03T19:52:14.443 に答える