프로그래밍/C#

[C#] StreamReader : 대용량 텍스트 파일 읽기

준코딩 2020. 9. 22. 07:20

 

 StreamReader 생성자

우선 StreamReader는 간편하게 파일을 읽어오고 싶을 때 사용하는 클래스입니다.

아래와 같이 생성하셔서 사용하시면 됩니다. 또한, 한글을 사용하자 하실 때는 인코딩 UTF8을 설정해주세요.

 

StreamReader sr = new StreamReader(FilePath, Encoding.UTF8);

 

 

 

 

 StreamReader 속성

 

 1. EndOfStream

 

:  현재 스트림 위치가 스트림의 끝에 있으면 true이고, 없으면 false입니다. 보통 속성은 " () " 를 사용하지 않고 메서드는 " () " 를 사용합니다.

 

 

 StreamReader 주요 메서드

 

 1. Read()

 

: 입력 스트림에서 다음 문자를 읽고 문자 위치를 한 문자씩 앞으로 이동합니다.

매개변수 없이 Read() 를 사용하는 경우 개체로 표시되는 입력 스트림의 다음 문자를 반환하게 되고, 사용할 수 있는 문자가 더 이상 없는 경우에는 -1을 반환하게 됩니다.

 

            while(sr.EndOfStream == false)
            {
                Console.WriteLine(sr.Read());
            }

 

 

2.  Read( Char [], Int32, Int32 )

 

: 현재 스트림에서 지정된 최대 문자를 지정된 인덱스부터 버퍼로 읽어 들입니다. 

Read 함수에 인자를 설정할 경우 읽어드린 문자의 수를 반환하고 매개변수인 Buffer에 읽어드린 내용을 저장합니다.

 

  • Char [] : buffer 변수
  • int32 : buffer의 시작 인덱스
  • int32 : buffer에 한 번에 담을 문자의 크기
            int bufferSize = 4096;
            char[] buffer = new char[bufferSize];

            while (sr.EndOfStream == false)
            {
                int CharCount = sr.Read(buffer, 0, bufferSize);
                Console.WriteLine("글자수 : " + CharCount + ", 내용 : " + buffer);
            }

 

 

3. ReadLine()

 

: 현재 스트림에서 한 줄의 문자를 읽고 데이터를 문자열로 반환합니다.

읽어드린 내용을 String으로 반환하기 때문에 즉시 출력이 가능합니다.

 

            while (sr.EndOfStream == false)
            {
                
                Console.WriteLine(sr.ReadLine());
            }

 

 

 

4. ReadToEnd()

 

: 가장 자주 사용하는 메서드로 현재 위치에서 마지막까지의 전체 내용을 String으로 반환해줍니다.

 

            string allOfContents = sr.ReadToEnd();
            Console.WriteLine(allOfContents);

 

 

 

 

 대용량 텍스트 파일 읽기

이제 대용량 텍스트를 읽는 방법입니다. 보통 ReadToEnd() 메서드를 사용하면 1GB  정도의 내용도 한 번에 읽는 것이 가능합니다. 하지만 10Gb, 100GB 로 내용이 커지면 OutOfMemory라는 오류가 발생하게 됩니다. 

 

결론만 말하자면 반복문을 사용하면서 읽어온 내용을 바로 쓰고 내용을 비워주는 작업이 필요합니다. 그러기 위해서는 StreamReader 와 StreamWriter 를 동시에 선언해서 사용해야 하는데, 코드를 보시면서 이해하시면 편할 것 같습니다. 

 

참고 : StreamWriter 의 생성자에서 파일 경로에 지정한 파일이 없는 경우 텍스트 파일을 만들어 저장하게 됩니다.

 

 

        StreamWriter sw = new StreamWriter(textBoxSnpFilePath.Text + ".new", false);
        StreamReader sr = new StreamReader(textBoxSnpFilePath.Text, Encoding.UTF8);

        int bufferSize = 4096; // Basic Stream Size
        int remainBuffer = 0;
        char[] buffer = new char[bufferSize];

        while(sr.EndOfStream == false)
        {
            remainBuffer = sr.Read(buffer, 0, bufferSize);

            if (sr.EndOfStream) break;
            sw.Write(buffer);
        }

        // write reamin contents
        for(int i=0; i< remainBuffer; i++)
        {
            sw.Write(buffer[i]);
        }

 

주의해야 할 부분은 Read() 메서드를 통해서 매번 4096개의 글자를 읽어드립니다. 하지만 마지막 부분은 정확히 나누어 떨어지는 글자 수가 아니라면 4096 보다 작은 문자 수를 읽어드리게 됩니다. 이때 직전에 읽어드렸던 내용들이 남아있게 되는데, 이 부분을 따로 for문을 돌려 처리해줄 필요가 있습니다. 언제나 질문은 댓글에 달아주시면 감사하겠습니다. ㅎㅎ