본문 바로가기
Language/Java

[JAVA] 데이터의 흐름을 지배하는 Java 스트림(Stream I/O) 완벽 가이드

by Papa Martino V 2026. 1. 19.
728x90

스트림(Stream I/O)
스트림(Stream I/O)

 

자바 프로그래밍에서 '데이터를 읽고 쓰는 작업'은 가장 기본적이면서도 중요한 핵심입니다. 파일에 로그를 기록하거나, 네트워크를 통해 채팅 메시지를 보내고, 사용자로부터 입력을 받는 모든 과정이 바로 스트림(Stream I/O)을 통해 이루어집니다. 본 포스팅에서는 단순히 이론적인 개념을 넘어, 자바 입출력 시스템의 구조와 실무에서 바로 활용 가능한 고급 기법들을 심도 있게 다룹니다.

1. Java 스트림(Stream I/O)의 본질적 개념

자바에서 I/O 스트림은 '데이터의 흐름'을 의미합니다. 마치 수도관을 흐르는 물처럼, 데이터가 출발지(Source)에서 목적지(Destination)로 순차적으로 전달되는 통로라고 이해하면 쉽습니다. 자바의 java.io 패키지는 이러한 단방향 통신을 지원하기 위해 설계되었습니다.

스트림의 주요 특징

  • 단방향성: 데이터는 한 방향으로만 흐릅니다. 입력을 위한 스트림(InputStream)과 출력을 위한 스트림(OutputStream)이 별도로 존재합니다.
  • FIFO(First-In, First-Out): 먼저 들어간 데이터가 먼저 나가는 순차적 구조를 가집니다.
  • 지연 불가능: 스트림은 데이터가 들어올 때까지 기다리거나(Blocking), 즉시 처리하는 동기적 성격을 기본으로 합니다.

2. 바이트 스트림 vs 문자 스트림: 언제 무엇을 쓸까?

자바 I/O의 가장 큰 분류는 처리하는 데이터의 단위에 따라 바이트(Byte)문자(Character)로 나뉩니다. 이 차이를 명확히 이해해야 데이터 깨짐 현상(특히 한글)을 방지할 수 있습니다.

구분 바이트 스트림 (Byte Stream) 문자 스트림 (Character Stream)
단위 8-bit (1 byte) 16-bit (2 byte, Unicode)
최상위 클래스 InputStream / OutputStream Reader / Writer
주요 용도 이미지, 동영상, 실행 파일 등 이진 데이터 텍스트 파일, HTML 등 문자 기반 데이터
특징 데이터를 있는 그대로 전달 인코딩(UTF-8 등)을 자동 처리

3. 성능의 핵심: 보조 스트림(Processing Stream)

기본 스트림만으로는 대용량 데이터를 처리할 때 속도가 현저히 떨어집니다. 이때 사용하는 것이 보조 스트림입니다. 보조 스트림은 실제 데이터를 읽고 쓰는 기능은 없지만, 기본 스트림에 '기능'을 추가해주는 데코레이터 패턴의 전형적인 예입니다. 가장 대표적인 것이 BufferedInputStream / BufferedReader입니다. 메모리 버퍼를 사용하여 입출력 횟수를 획기적으로 줄여줌으로써 성능을 극대화합니다.

4. 실전 코드 예제 (Sample Example)

다음은 실무에서 텍스트 파일을 읽어들일 때 가장 권장되는 방식인 BufferedReadertry-with-resources 구문을 사용한 예제입니다.


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class StreamExample {
    public static void main(String[] args) {
        // try-with-resources: 자동으로 스트림을 닫아줌 (Java 7+)
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            System.out.println("파일 내용을 읽어옵니다:");
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("파일을 읽는 중 오류가 발생했습니다: " + e.getMessage());
        }
    }
}

5. 현대적인 자바 I/O: NIO (New I/O)와의 차이

Java 1.4부터 도입된 java.nio는 기존 I/O의 블로킹 방식 한계를 극복하기 위해 등장했습니다. NIO는 채널(Channel)과 버퍼(Buffer)를 기반으로 하며, 비블로킹(Non-blocking) 처리가 가능해 대규모 연결이 필요한 네트워크 서버 구현에 적합합니다. 단순한 파일 읽기/쓰기라면 IO가 직관적이지만, 고성능 서비스라면 NIO를 고려해야 합니다.

6. 결론 및 요약

Java의 I/O 시스템은 그 역사가 깊은 만큼 견고하고 체계적입니다. 데이터의 성격(바이트/문자)을 먼저 파악하고, 보조 스트림을 통해 성능을 최적화하며, try-with-resources를 통해 자원 누수를 방지하는 것이 자바 개발자의 필수 덕목입니다.


출처 및 참고문헌

  • Oracle Java Documentation: java.io Package
  • The Java™ Tutorials: Essential Classes - I/O Streams
  • Effective Java 3rd Edition (Joshua Bloch)
728x90