IT story

.NET에서 대용량 (1GB) txt 파일을 읽는 방법은 무엇입니까?

hot-time 2021. 1. 6. 20:22
반응형

.NET에서 대용량 (1GB) txt 파일을 읽는 방법은 무엇입니까?


한 줄씩 읽어야하는 1GB 텍스트 파일이 있습니다. 이를 수행하는 가장 좋고 빠른 방법은 무엇입니까?

private void ReadTxtFile()
{            
    string filePath = string.Empty;
    filePath = openFileDialog1.FileName;
    if (string.IsNullOrEmpty(filePath))
    {
        using (StreamReader sr = new StreamReader(filePath))
        {
            String line;
            while ((line = sr.ReadLine()) != null)
            {
                FormatData(line);                        
            }
        }
    }
}

에서는 FormatData()I 워드와 일치하고 증분 정수 변수에 기초해야 라인의 시작 단어를 확인한다.

void FormatData(string line)
{
    if (line.StartWith(word))
    {
        globalIntVariable++;
    }
}

.NET 4.0을 사용 하는 경우이 시나리오를 위해 설계된 클래스 인 MemoryMappedFile사용해보십시오 .

StreamReader.ReadLine그렇지 않으면 사용할 수 있습니다 .


StreamReader를 사용하는 것은 전체 파일을 한 번에 메모리에 저장하는 것을 원하지 않기 때문에 아마도 그 방법 일 것입니다. MemoryMappedFile은 순차 읽기보다 랜덤 액세스에 더 적합합니다 (순차 읽기의 경우 10 배 빠르며 메모리 매핑은 랜덤 액세스의 경우 10 배 빠름).

FileOptions가 SequentialScan ( FileOptions Enumeration 참조)으로 설정된 파일 스트림에서 streamreader를 만들 수도 있지만 큰 차이가있을 것 같지 않습니다.

그러나 읽기와 동일한 루프에서 서식을 지정하기 때문에 예제를 더 효과적으로 만드는 방법이 있습니다. 클록 사이클을 낭비하고 있으므로 더 많은 성능을 원하면 한 스레드가 데이터를 읽고 다른 스레드가 데이터를 사용할 수있게되면 형식을 지정하는 다중 스레드 비동기 솔루션을 사용하는 것이 좋습니다. 필요에 맞는 Checkout BlockingColletion :

수집 차단 및 생산자-소비자 문제

가능한 가장 빠른 성능을 원한다면 내 경험상 유일한 방법은 큰 이진 데이터 청크를 순차적으로 읽고 병렬로 텍스트로 역 직렬화하는 것입니다.하지만 코드는 그 시점에서 복잡해지기 시작합니다.


LINQ 를 사용할 수 있습니다 .

int result = File.ReadLines(filePath).Count(line => line.StartsWith(word));

File.ReadLines전체 파일을 메모리에로드하지 않고 파일에서 각 줄을 느리게 읽는 IEnumerable <String>반환합니다 .

Enumerable.Count 는 단어로 시작하는 줄을 계산합니다.

UI 스레드에서 호출하는 경우 BackgroundWorker를 사용하십시오 .


아마 한 줄씩 읽을 것입니다.

끝까지 읽은 다음 처리하여 강제로 메모리에 저장하지 마십시오.


StreamReader.ReadLine잘 작동합니다. 프로파일 링을 통해 더 잘할 수 있다는 것을 알지 못하는 경우 프레임 워크가 버퍼링을 선택하도록합니다.


TextReader.ReadLine()


Agenty 의 프로덕션 서버에서 큰 파일 (때로는 10-25GB (\ t) 탭으로 구분 된 txt 파일)이 표시되는 동일한 문제에 직면했습니다 . 많은 테스트와 연구 끝에 for / foreach 루프를 사용하여 큰 파일을 작은 청크로 읽고 File.ReadLines ()로 오프셋 및 제한 논리를 설정하는 가장 좋은 방법을 찾았습니다.

int TotalRows = File.ReadLines(Path).Count(); // Count the number of rows in file with lazy load
int Limit = 100000; // 100000 rows per batch
for (int Offset = 0; Offset < TotalRows; Offset += Limit)
{
  var table = Path.FileToTable(heading: true, delimiter: '\t', offset : Offset, limit: Limit);

 // Do all your processing here and with limit and offset and save to drive in append mode
 // The append mode will write the output in same file for each processed batch.

  table.TableToFile(@"C:\output.txt");
}

내 Github 라이브러리에서 전체 코드를 참조하십시오 : https://github.com/Agenty/FileReader/

전체 공개-저는이 라이브러리와 웹 사이트를 소유 한 회사 인 Agenty에서 일합니다.


한 번에 10,000 바이트 파일을 읽었습니다. 그런 다음 10,000 바이트를 분석하여 줄로 잘라서 FormatData 함수에 제공합니다.

Bonus points for splitting the reading and line analysation on multiple threads.

I'd definitely use a StringBuilder to collect all strings and might build a string buffer to keep about 100 strings in memory all the time.


My file is over 13 GB:

enter image description here

You can use my class:

public static void Read(int length)
    {
        StringBuilder resultAsString = new StringBuilder();

        using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(@"D:\_Profession\Projects\Parto\HotelDataManagement\_Document\Expedia_Rapid.jsonl\Expedia_Rapi.json"))
        using (MemoryMappedViewStream memoryMappedViewStream = memoryMappedFile.CreateViewStream(0, length))
        {
            for (int i = 0; i < length; i++)
            {
                //Reads a byte from a stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
                int result = memoryMappedViewStream.ReadByte();

                if (result == -1)
                {
                    break;
                }

                char letter = (char)result;

                resultAsString.Append(letter);
            }
        }
    }

This code will read text of file from start to the length that you pass to the method Read(int length) and fill the resultAsString variable.

It will return the bellow text:

ReferenceURL : https://stackoverflow.com/questions/4273699/how-to-read-a-large-1-gb-txt-file-in-net

반응형