텍스트 파일을 한 줄씩 읽는 가장 빠른 방법은 무엇입니까?

텍스트 파일을 한 줄씩 읽고 싶습니다. .NET C # 범위 내에서 가능한 한 효율적으로하고 있는지 알고 싶었습니다.

이것이 지금까지 시도한 것입니다.

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}



답변

파일을 한 줄씩 읽는 가장 빠른 방법을 찾으려면 벤치마킹을 수행해야합니다. 컴퓨터에서 몇 가지 작은 테스트를 수행했지만 결과가 환경에 적용되는 것을 기대할 수 없습니다.

StreamReader.ReadLine 사용

이것은 기본적으로 당신의 방법입니다. 어떤 이유로 버퍼 크기를 가능한 가장 작은 값 (128)으로 설정했습니다. 이를 늘리면 일반적으로 성능이 향상됩니다. 기본 크기는 1,024이고 다른 좋은 선택은 512 (Windows의 섹터 크기) 또는 4,096 (NTFS의 클러스터 크기)입니다. 최적의 버퍼 크기를 결정하려면 벤치 마크를 실행해야합니다. 더 큰 버퍼는 더 빠르지는 않지만 적어도 작은 버퍼보다 ​​느리지 않습니다.

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
      // Process line
  }

FileStream생성자를 지정할 수 있습니다 FileOptions을 . 예를 들어, 큰 파일을 처음부터 끝까지 순차적으로 읽는 경우 이점이있을 수 있습니다 FileOptions.SequentialScan. 다시 한 번 벤치마킹이 최선의 방법입니다.

File.ReadLines 사용

이것은 StreamReader고정 버퍼 크기 1,024를 사용하여 구현된다는 점을 제외하고는 자체 솔루션과 매우 유사합니다 . 내 컴퓨터에서는 버퍼 크기가 128 인 코드와 비교하여 약간 더 나은 성능을 제공합니다. 그러나 더 큰 버퍼 크기를 사용하면 동일한 성능 향상을 얻을 수 있습니다. 이 방법은 반복자 블록을 사용하여 구현되며 모든 라인에 메모리를 사용하지는 않습니다.

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

File.ReadAllLines 사용

이 방법은 반환 된 행 배열을 만드는 데 사용되는 문자열 목록을 늘려 메모리 요구 사항이 더 높다는 점을 제외하면 이전 방법과 매우 유사합니다. 그러나 임의로 리턴 하여 회선에 액세스 할 수 는 String[]없습니다 IEnumerable<String>.

var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
  var line = lines[i];
  // Process line
}

String.Split 사용

이 방법은 아마도 String.Split구현 방법으로 인해 적어도 큰 파일 (511KB 파일에서 테스트 됨)에서 상당히 느립니다 . 또한 솔루션에 비해 필요한 메모리를 늘리는 모든 라인에 배열을 할당합니다.

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

File.ReadLines깨끗하고 효율적이기 때문에 사용 하는 것이 좋습니다. 특별한 공유 옵션이 필요한 경우 (예 FileShare.ReadWrite🙂 자체 코드를 사용할 수 있지만 버퍼 크기를 늘려야합니다.


답변

.NET 4를 사용 File.ReadLines하는 경우 간단하게 사용 하십시오. 나는 그것이 또한 사용 하고 큰 버퍼 (128은 매우 작은 것)를 제외하고는 당신과 거의 동일 하다고 생각합니다 FileOptions.SequentialScan.


답변

File.ReadAllLines()파일을 읽는 가장 간단한 방법 중 하나 이지만 가장 느린 방법 중 하나입니다.

이 벤치 마크에 따르면 많은 일을하지 않고 파일에서 행 을 읽으려면 파일을 읽는 가장 빠른 방법은 다음과 같은 오래된 방법입니다.

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do minimal amount of work here
        }
}

그러나 각 줄을 많이 사용해야하는 경우이 기사에서는 가장 좋은 방법은 다음과 같다는 결론을 내립니다 (그리고 읽을 줄 수를 알고 있으면 string []을 미리 할당하는 것이 더 빠릅니다).

AllLines = new string[MAX]; //only allocate memory here

using (StreamReader sr = File.OpenText(fileName))
{
        int x = 0;
        while (!sr.EndOfStream)
        {
               AllLines[x] = sr.ReadLine();
               x += 1;
        }
} //Finished. Close the file

//Now parallel process each line in the file
Parallel.For(0, AllLines.Length, x =>
{
    DoYourStuff(AllLines[x]); //do your work here
});


답변

다음 코드를 사용하십시오.

foreach (string line in File.ReadAllLines(fileName))

이는 읽기 성능면에서 큰 차이였습니다.

메모리 소비 비용이 들지만 그만한 가치가 있습니다!


답변

스택 오버플로 질문에서 이것에 대해 좋은 주제가 있습니다. ‘수율 반환’이 “구식”반환보다 느립니까? .

그것은 말한다 :

ReadAllLines는 모든 행을 메모리에로드하고 문자열 []을 반환합니다. 파일이 작 으면 좋습니다. 파일이 메모리에 맞는 것보다 큰 경우 메모리가 부족합니다.

반면에 ReadLine은 한 번에 한 줄씩 반환하기 위해 yield return을 사용합니다. 그것으로, 당신은 어떤 크기의 파일을 읽을 수 있습니다. 전체 파일을 메모리에로드하지 않습니다.

“foo”라는 단어가 포함 된 첫 번째 줄을 찾은 다음 종료한다고 가정합니다. ReadAllLines를 사용하면 첫 번째 줄에 “foo”가 발생하더라도 전체 파일을 메모리로 읽어야합니다. ReadLines를 사용하면 한 줄만 읽습니다. 어느 쪽이 더 빠를까요?


답변

파일 크기가 크지 않으면 전체 파일을 읽고 나중에 분할하는 것이 더 빠릅니다.

var filestreams = sr.ReadToEnd().Split(Environment.NewLine,
                              StringSplitOptions.RemoveEmptyEntries);


답변

메모리가 충분하면 전체 파일을 메모리 스트림 으로 읽은 다음 스트림 리더를 열어 줄을 읽음 으로써 성능이 약간 향상되었습니다 . 어쨌든 전체 파일을 실제로 읽을 계획이라면 몇 가지 개선이 이루어질 수 있습니다.