1か月のログファイルが1つあります。これらのファイルは、以下のスニペットのように、各ラインのいくつかの情報を持つプレーンテキストです:大きなテキストファイル(400万行以上)を読み込み、.NETの各行を解析する
1?2017-06-01T00:00:00^148^3
2?myVar1^3454.33
2?myVar2^35
2?myVar3^0
1?2017-06-01T00:00:03^148^3
...
を処理し、このデータを表示するために、私はこれらのtxtファイルを読み込み、WPFアプリケーションを開発しています、ラインを解析し、このデータを保存SQLiteデータベースに保存します。次に、ユーザーがサブセットのAVGのような基本的な数学演算を行うことを許可します。
これらのファイルは大きすぎます(それぞれ300mb以上400万行以上)ので、私はProcessLine
メソッドのメモリ使用に苦労しています。メソッドは決して終了せず、アプリケーションは単独でブレークモードに入ります。
マイコード:
private bool ParseContent(string filePath)
{
if (string.IsNullOrEmpty(FilePath) || !File.Exists(FilePath))
return false;
string logEntryDateTimeTemp = string.Empty;
string [] AllLines = new string[5000000]; //only allocate memory here
AllLines = File.ReadAllLines(filePath);
Parallel.For(0, AllLines.Length, x =>
{
ProcessLine(AllLines[x], ref logEntryDateTimeTemp);
});
return true;
}
void ProcessLine(string line, ref string logEntryDateTimeTemp)
{
if (string.IsNullOrEmpty(line))
return;
var logFields = line.Split(_delimiterChars);
switch (logFields[0])
{
case "1":
logEntryDateTimeTemp = logFields[1];
break;
case "2":
LogEntries.Add(new LogEntry
{
Id = ItemsCount + 1,
CurrentDateTime = logEntryDateTimeTemp,
TagAddress = logFields[1],
TagValue = Convert.ToDecimal(logFields[2])
});
ItemsCount++;
break;
default:
break;
}
}
はそれを行うための良い方法はありますか?
OBS:
#region StreamReader
//using (StreamReader sr = File.OpenText(filePath))
//{
// string line = String.Empty;
// while ((line = sr.ReadLine()) != null)
// {
// if (string.IsNullOrEmpty(line))
// break;
// var logFields = line.Split(_delimiterChars);
// switch (logFields[0])
// {
// case "1":
// logEntryDateTimeTemp = logFields[1];
// break;
// case "2":
// LogEntries.Add(new LogEntry
// {
// Id = ItemsCount + 1,
// CurrentDateTime = logEntryDateTimeTemp,
// TagAddress = logFields[1],
// TagValue = Convert.ToDecimal(logFields[2])
// });
// ItemsCount++;
// break;
// default:
// break;
// }
// }
//}
#endregion
#region ReadLines
//var lines = File.ReadLines(filePath, Encoding.UTF8);
//foreach (var line in lines)
//{
// if (string.IsNullOrEmpty(line))
// break;
// var logFields = line.Split(_delimiterChars);
// switch (logFields[0])
// {
// case "1":
// logEntryDateTimeTemp = logFields[1];
// break;
// case "2":
// LogEntries.Add(new LogEntry
// {
// Id = ItemsCount + 1,
// CurrentDateTime = logEntryDateTimeTemp,
// TagAddress = logFields[1],
// TagValue = Convert.ToDecimal(logFields[2])
// });
// ItemsCount++;
// break;
// default:
// break;
// }
//}
#endregion
OBS2::私は、Visual Studio 2017を使用していて、アプリケーションをデバッグモードで実行されている場合、私はあるファイルを読み込むための2つの他の方法を、またテストしてみましたアプリケーションが突然中断モードに入り、次のように出力ウィンドウにメッセージを読み取ります
CLRは60秒間COM コンテキスト0xb544f0にCOMコンテキスト0xb545a8から移行することができませんでした。宛先 コンテキスト/アパートメントを所有するスレッドは、ポンピングすることなく、非常に長い実行中の操作を 処理中である可能性があります。 メッセージ。このような状況は、一般的に負のパフォーマンスの影響を受け、アプリケーションが応答しなくなったり、時間の経過とともにメモリが継続的に累積することさえあります。この問題を回避するには、 シングルスレッドアパートメント(STA)スレッドはすべて、ポンプ待機の プリミティブ(CoWaitForMultipleHandlesなど)を使用し、長時間実行する操作ではメッセージ を定期的に送信する必要があります。
私はいくつかの質問をしていますが、最初にそのファイルがなぜそれほど大きいのですか? –
はい、これを実行する方がはるかに優れています - 一度に1行ずつ読み込み、すべてを一度にメモリに読み込もうとするのではなく、あなたの2番目のアプローチは、テキストファイル全体を読み取ることはありませんが、まだ行にエントリを持つメモリ内のコレクションを構築するようです... –
@JonSkeetそれは、コレクションのサイズがどうにかしてアプリケーションを中断させる原因になる要素の数が高すぎるために多くのメモリを占有していますか? –