3

非標準の区切り文字(コンマ/引用符またはタブ区切りではない)を持ついくつかの区切られたテキストファイルを処理しようとしています。区切り文字はランダムなASCII文字であり、区切り文字の間に頻繁に表示されることはありません。調べてみたところ、.NETで自分のニーズに合うソリューションは見つからなかったようです。このために作成されたカスタムライブラリには、巨大な入力(いくつかのフィールド値を持つ4GBファイル)に関していくつかの欠陥があるようです。非常に簡単に数百万文字)。

これは少し極端に思えますが、実際には、一部のレビューソフトウェアがドキュメントの完全なコンテンツを含むフィールド値を持つことは、電子ドキュメントディスカバリー(EDD)業界の標準です。参考までに、私は以前、問題なくcsvモジュールを使用してPythonでこれを実行しました。

入力例は次のとおりです。

Field delimiter = 
quote character = þ

þFieldName1þþFieldName2þþFieldName3þþFieldName4þ
þValue1þþValue2þþValue3þþSomeVery,Very,Very,Large value(5MB or so)þ
...etc...

編集:それで、私は先に進んで、区切られたファイルパーサーを最初から作成しました。バグが発生しやすいので、このソリューションを使用するのはちょっとうんざりです。また、このようなタスクのために独自のパーサーを作成する必要があることは、「エレガント」または正しいとは感じません。とにかくパーサーを一から書く必要はなかったのではないかと思います。

4

6 に答える 6

5

ファイル ヘルパー APIを使用します。これは .NET であり、オープン ソースです。コンパイルされた IL コードを使用して厳密に型指定されたオブジェクトにフィールドを設定することで、非常に高いパフォーマンスを実現し、ストリーミングをサポートします。

あらゆる種類のファイル タイプとカスタム区切り文字をサポートしています。4GBを超えるファイルを読み取るために使用しました。

何らかの理由でそれができない場合は、string.split を使用して行ごとに読み取ってみてください。

public IEnumerable<string[]> CreateEnumerable(StreamReader input)
{
    string line;
    while ((line = input.ReadLine()) != null)
    {
        yield return line.Split('þ');
    }
}

これにより、ラインを表す単純な文字列配列が得られ、Linq を使用することもできます ;) ただし、IEnumerable は遅延ロードされるので、反復するまで (またはToList/ToArray などのフルロード操作 - ただし、ファイルサイズを考えると、そうしないと思います!)。

良い使用例を次に示します。

using (StreamReader sr = new StreamReader("c:\\test.file"))
{
    var qry = from l in CreateEnumerable(sr).Skip(1)
              where l[3].Contains("something")
              select new { Field1 = l[0], Field2 = l[1] };
    foreach (var item in qry)
    {
        Console.WriteLine(item.Field1 + " , " + item.Field2);
    }
}
Console.ReadLine();

これにより、ヘッダー行がスキップされ、ファイルから最初の 2 つのフィールドが出力されます。4 番目のフィールドには、"something" という文字列が含まれています。ファイル全体をメモリにロードせずにこれを行います。

于 2008-12-04T03:08:03.493 に答える
1

Windowsと高性能I/Oは、IO完了ポートを使用することを意味します。あなたはそれをあなたのケースで機能させるためにいくつかの余分な配管をしなければならないかもしれません。

これは、C#/。NETを使用することを理解した上で、JoeDuffyによると

18)マネージコードでWindows非同期プロシージャコール(APC)を使用しないでください。

私はそれを難し​​い方法で学ばなければなりませんでした;)、しかしAPCの使用を除外すると、IOCPが唯一の正しいオプションです。また、ソケットサーバーで頻繁に使用される他の多くのタイプのI/Oもサポートします。

実際のテキストを解析する限り、合理化されたストリームの使用については、EricWhiteのブログをチェックしてください。

于 2009-09-30T11:53:34.193 に答える
0

私は、メモリ マップ ファイル (ここでは msdn が .NET ラッパーを指す) と単純なインクリメンタル パースの組み合わせを使用して、レコード/テキスト行 (または何でも) の IEnumerable リストに戻す傾向があります。

于 2008-12-04T03:15:37.490 に答える
0

カスタムパーサーを作成することに問題はありません。要件は、BCL によって既に提供されているものとは十分に異なっているように見えるので、すぐに進めてください。

「エレガンス」は明らかに主観的なものです。私の意見では、パーサーの API が標準の BCL の「リーダー」タイプの API のように見えて機能する場合、それは非常に「エレガント」です。

大きなデータ サイズについては、一度に 1 バイトずつ読み取ってパーサーを機能させ、単純なステート マシンを使用して何をすべきかを判断します。FileStreamストリーミングとバッファリングは基になるクラスに任せます。パフォーマンスとメモリ消費は問題ないはずです。

このようなパーサー クラスの使用例:

using(var reader = new EddReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)) {
    // Read a small field
    string smallField = reader.ReadFieldAsText();
    // Read a large field
    Stream largeField = reader.ReadFieldAsStream();
}
于 2009-09-30T12:09:53.310 に答える
0

一部のフィールドは非常に大きいと述べていますが、それらを完全にメモリに読み取ろうとすると、問題が発生する可能性があります。ファイルを 8K (または小さなチャンク) で読み取り、現在のバッファーを解析し、状態を追跡します。

解析しているこのデータで何をしようとしていますか? 何かを探していますか?変形させていますか?

于 2008-12-04T05:46:58.290 に答える
-1

これは大量の入力の問題に対処するのに役立ちませんが、解析の問題に対する可能な解決策には、戦略パターンを使用して区切り文字を提供するカスタム パーサーが含まれる場合があります。

于 2008-12-04T03:04:04.533 に答える