Input Output 스트림

유방현·2024년 10월 28일

1. 스트림(Stream)의 기본 개념

1.1 정의

  • 데이터의 흐름을 추상화한 개념
  • 순차적인 데이터 입출력을 위한 통로
  • 단방향 데이터 전송 채널

1.2 스트림의 기본 구분

  1. 입력 스트림 (Input Stream)

    • 외부에서 데이터를 읽어오는 스트림
    • 파일 읽기, 키보드 입력 등
  2. 출력 스트림 (Output Stream)

    • 외부로 데이터를 출력하는 스트림
    • 파일 쓰기, 콘솔 출력 등

2. 스트림의 종류

2.1 데이터 형태에 따른 구분

  1. 바이트 스트림
// 바이트 스트림 예시
FileInputStream fis = new FileInputStream("test.dat");
FileOutputStream fos = new FileOutputStream("output.dat");
  • 8비트 단위로 데이터 처리
  • 모든 종류의 데이터 처리 가능
  • 이미지, 동영상 등 바이너리 데이터 처리에 적합
  1. 문자 스트림
// 문자 스트림 예시
FileReader reader = new FileReader("text.txt");
FileWriter writer = new FileWriter("output.txt");
  • 16비트 단위로 데이터 처리
  • 텍스트 데이터 처리에 특화
  • 유니코드 문자 처리 가능

2.2 기능에 따른 구분

  1. 주 스트림 (Primary Stream)
// 주 스트림 예시
FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
  • 데이터 입출력을 직접 담당
  • 실제 데이터 소스와 직접 연결
  1. 보조 스트림 (Secondary Stream)
// 보조 스트림 예시
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.txt"));
  • 주 스트림에 추가 기능 제공
  • 버퍼링, 데이터 변환 등 지원

3. 버퍼링과 성능 최적화

3.1 버퍼의 필요성

  • 입출력 장치와 프로그램 간의 속도 차이 보완
  • 데이터를 일정량 모아서 한 번에 처리
  • 입출력 횟수 감소로 성능 향상

3.2 버퍼 스트림 활용

public class BufferedStreamExample {
    public void readWithBuffer() {
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("input.txt"))) {
            int data;
            while ((data = bis.read()) != -1) {
                // 버퍼를 통한 효율적인 읽기
                System.out.print((char)data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 예외 처리와 리소스 관리

4.1 기본 예외 처리 구조

FileInputStream fis = null;
try {
    fis = new FileInputStream("file.txt");
    // 파일 처리 로직
} catch (IOException e) {
    // 예외 처리
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.2 try-with-resources 활용

try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 파일 처리 로직
} catch (IOException e) {
    // 예외 처리
}

5. 주요 사용 패턴

5.1 파일 복사

public void copyFile(String source, String target) {
    try (FileInputStream fis = new FileInputStream(source);
         FileOutputStream fos = new FileOutputStream(target)) {
        int data;
        while ((data = fis.read()) != -1) {
            fos.write(data);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

5.2 텍스트 파일 처리

public void processTextFile(String filename) {
    try (BufferedReader reader = new BufferedReader(
            new FileReader(filename))) {
        String line;
        while ((line = reader.readLine()) != null) {
            // 텍스트 처리 로직
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

버퍼를 사용하는 이유

컴퓨터의 입출력 장치(디스크, 네트워크, 키보드 등)와 프로그램 간에는 속도 차이가 큽니다. 프로그램이 처리 속도가 빠른 반면, 입출력 장치의 속도는 상대적으로 느리기 때문에, 작은 데이터를 여러 번 주고받을 경우 성능 저하가 발생할 수 있습니다.

버퍼를 사용하면 데이터를 한 번에 모아서 처리하여 입출력 작업의 빈도를 줄이고, 전체적인 성능을 개선할 수 있습니다. 이는 자바의 파일 IO 작업에서 특히 중요합니다.

  • 버퍼를 사용하지 않는 입출력은 우편 배달부가 편지를 하나씩 배달하는 것과 같습니다. 매번 배달할 때마다 시간이 걸립니다.
  • 버퍼를 사용하는 입출력은 편지를 일정량 모아서 한 번에 배달하는 것과 비슷합니다. 더 적은 배달 횟수로 더 많은 편지를 처리할 수 있습니다.

0개의 댓글