1. Java I/O 기본 구조
1.1 Stream의 분류
자바의 입출력 스트림은 크게 두 가지 계열로 나뉩니다.
- 바이트 스트림(Byte Stream)
- 최상위 클래스: InputStream, OutputStream
- 1바이트 단위로 입출력
- 대상: 파일, 네트워크, 이미지, 바이너리 등
- 문자 스트림(Character Stream)
- 최상위 클래스: Reader, Writer
- 2바이트 유니코드 문자 단위로 입출력
- 대상: 텍스트 기반 입출력
1.2 공통 특징
- Closeable 인터페이스 구현: 스트림은 외부 자원을 사용하므로 명시적으로 close() 호출 필요.
- Flushable 인터페이스: OutputStream, Writer 등 출력 스트림은 버퍼에 데이터를 모았다가 flush()로 전송 가능.
2. 주요 클래스 기능 및 차이
2.1 InputStream / OutputStream
| 클래스 | 주요 메서드 | 설명 |
| InputStream | read(), read(byte[]), close() | 1바이트씩 또는 배열 단위로 읽음 |
| OutputStream | write(int), write(byte[]), flush() | 바이트 단위 출력. flush는 버퍼의 내용을 강제로 출력 |
→ 예: FileInputStream, BufferedInputStream, ByteArrayOutputStream 등
2.2 Reader / Writer
| 클래스 | 주요 메서드 | 설명 |
| Reader | read(), read(char[]), close() | 유니코드 문자 단위 읽기 |
| Writer | write(int), write(char[]), flush() | 문자 단위 출력 + flush |
| Writer | append(CharSequence) | Appendable 구현으로 문자열 추가 가능 |
→ 예: FileReader, BufferedReader, StringWriter, PrintWriter 등
3. Buffered 계열 클래스
3.1 BufferedInputStream / BufferedReader
- 버퍼를 활용한 I/O 성능 개선
- 내부 버퍼(byte[] 또는 char[])에 읽고, 거기서 한 줄씩 읽는 방식
- BufferedReader.readLine() 은 한 줄 단위로 읽기 때문에 많이 사용됨
- Scanner보다 더 빠르다 (I/O 처리 기준)
3.2 Scanner와의 차이
| 항목 | BufferedReader | Scanner |
| 속도 | 빠름 | 상대적으로 느림 |
| 사용성 | 단순 텍스트 라인 처리 | 다양한 자료형 파싱 지원 |
| 정규표현식 | 지원 안함 | 지원함 |
4. Java 7부터 추가된 NIO.2 (java.nio.file.Files)
4.1 주요 장점
- 간단한 API
- 파일 전체 읽기/쓰기, 디렉토리 조작, 속성 확인 등 많은 기능 지원
- Paths.get() + Files 조합으로 매우 간결하게 코드 작성 가능
4.2 자주 쓰이는 메서드
// 전체 파일을 String으로 읽기
String content = new String(Files.readAllBytes(Paths.get("file.txt")), StandardCharsets.UTF_8);
// 한 줄씩 읽기
List<String> lines = Files.readAllLines(Paths.get("file.txt"), StandardCharsets.UTF_8);
// 파일 쓰기 (기존 내용 덮어씀)
Files.write(Paths.get("file.txt"), "내용".getBytes());
4.3 NIO vs 기존 I/O
| 항목 | java.io | java.nio.file (NIO.2) |
| 방식 | Stream 기반 순차 처리 | 채널 및 버퍼 기반 |
| 비동기 지원 | 불가 | 가능 (AsynchronousFileChannel) |
| API 단순성 | 복잡 | 간결함 |
5. 최근 발전: Java 11~21 I/O 주요 변화
5.1 Java 11 이후의 주요 추가
- Files.readString(Path) / Files.writeString(Path, String)
→ 문자열 전체를 더 쉽게 다룰 수 있음 (Java 11)
String s = Files.readString(Path.of("a.txt")); // Java 11
Files.writeString(Path.of("a.txt"), "내용"); // Java 11
- InputStream.transferTo(OutputStream out)
→ 스트림 복사를 더 쉽게 (Java 9 이상)
try (InputStream in = new FileInputStream("a.txt");
OutputStream out = new FileOutputStream("b.txt")) {
in.transferTo(out);
}
6. 주요 설계 및 실무 포인트
6.1 리소스 관리
- try-with-resources (Java 7+)
try (BufferedReader reader = new BufferedReader(new FileReader("a.txt"))) {
String line = reader.readLine();
}
- 자동으로 close() 처리 → 리소스 누수 방지
6.2 flush()의 의미
- OutputStream 또는 Writer는 내부에 버퍼가 있음
- flush()는 버퍼의 내용을 강제로 출력 (파일, 네트워크 등)
- BufferedWriter나 PrintWriter에선 주기적으로 flush 필요
writer.write("Hello");
writer.flush(); // 안 하면 바로 안 써질 수 있음
7. InputStream vs Reader 차이점 정리
| 항목 | InputStream | Reader |
| 처리 단위 | 바이트 (byte) | 문자 (char, 2byte) |
| 대상 | 바이너리 파일, 이미지 등 | 텍스트 파일 |
| 인코딩 처리 | 직접 처리 필요 | 자동 인코딩 처리 |
| 대표 클래스 | FileInputStream, BufferedInputStream | FileReader, BufferedReader |
→ 바이너리는 InputStream, 텍스트는 Reader
8. 요약 및 결론
자바에서 I/O를 다룰 때 고려할 점
- Stream은 바이트 / 문자 계열로 구분됨
- 버퍼링은 속도 향상을 위해 중요
- 자바 7 이후 NIO의 Files, Paths 클래스 사용이 권장됨
- 자바 11 이상이면 readString, writeString 등으로 한결 더 간결
- close()는 반드시 처리하거나 try-with-resources로 자동화
- flush()는 출력 버퍼 강제 비우기
부록: 참고 클래스 구조
java.io
│
├── InputStream (abstract)
│ ├── FileInputStream
│ └── BufferedInputStream
│
├── OutputStream (abstract)
│ ├── FileOutputStream
│ └── BufferedOutputStream
│
├── Reader (abstract)
│ ├── FileReader
│ └── BufferedReader
│
├── Writer (abstract)
│ ├── FileWriter
│ └── BufferedWriter
'기타 > 자바의 신' 카테고리의 다른 글
| (자바)자바 쓰레드(Thread) 완전 정리 *자바의 신 (2) | 2025.07.11 |
|---|---|
| (자바) 컬렉션 관련 정리 (자바의신 day9) (0) | 2025.07.06 |
| (자바) 내부 클래스란? (자바의 신 day7) (1) | 2025.07.01 |
| (자바)자바의 신 day6 - Java String 완벽 정리: intern(), 문자열 덧셈, 최적화 (0) | 2025.06.29 |
| (자바) 자바의 신 day5 - 자바에서 업캐스팅과 다운캐스팅, equals와 hashCode, toString의 역할 및 오버라이딩 이유 (0) | 2025.06.25 |