각 달의 로그 파일이 하나씩 있습니다. 이 파일은 아래의 조각 같은 각 라인에 약간의 정보와 일반 텍스트입니다큰 텍스트 파일 (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 : 나는 또한있는 파일을 읽기위한 두 가지 다른 방법을 테스트 한 응용 프로그램이 디버그 모드에서 실행 중일 때 나는 비주얼 스튜디오 2017을 사용하고있어 애플리케이션이 갑자기 중단 모드로 진입 한 다음 출력 창에 메시지를 읽
CLR을 60 초 동안 COM에 COM 컨텍스트 0xb545a8에서 컨텍스트 0xb544f0을 전환 할 수 없었다. 대상 컨텍스트/아파트를 소유하는 스레드는 펌핑 대기없이 수행하거나 서버 을 펌핑하지 않고 매우 오래 실행중인 작업을 처리하는 중 가장 가능성이 큽니다. 이 상황은 일반적으로 부정적인 성능 영향 을 가지며 응용 프로그램이 응답하지 않거나 시간이 지남에 따라 계속 사용량이 누적 될 수도 있습니다. 이 문제를 방지하려면 단일 스레드 아파트 (STA) 스레드는 펌핑 대기 프리미티브 (예 : CoWaitForMultipleHandles)를 사용하고 장시간 실행하는 동안 정기적으로 메시지 을 보내야합니다.
두 가지 질문이 있습니다. 그 중 첫 번째로 파일이 너무 큰 이유는 무엇입니까? –
네, 훨씬 더 좋은 방법이 있습니다 - 한 번에 한 줄씩 읽으십시오. 한 번에 모든 것을 메모리로 읽어들이려고하는 것이 아닙니다. 두 번째 접근 방식은 전체 텍스트 파일을 읽지는 않지만 여전히 메모리에 행을 하나씩 저장하는 콜렉션을 구축하는 것 같습니다. –
@JonSkeet 콜렉션의 크기가 어쨌든 응용 프로그램을 중단시키는 원인이 될 수 있습니까? 요소 수가 너무 많아서 많은 메모리를 차지하기 때문에? –