입출력 스트림(I/O streams)은 Java의 기본 개념 중 하나로, 언어의 초기 버전부터 존재해왔습니다. 이 개념은 데이터 읽기 및 쓰기 프로세스를 추상화하기 위해 처음 설계되었습니다: 스트림은 파일, 네트워크 또는 심지어 콘솔과 연결될 수 있으며, 코드에서 이들은 동일하게 보입니다.
문제는 개발자가 스트림을 잘못 관리하여 닫는 것을 잊거나 다양한 유형의 스트림(문자 스트림과 바이트 스트림)을 혼동할 때 발생하며, 이는 종종 리소스 누수, 데이터 왜곡 또는 실행 중 오류로 이어질 수 있습니다.
해결책은 입출력 스트림의 계층 구조(InputStream/OutputStream는 바이트, Reader/Writer는 문자에 해당)에 대한 올바른 이해와 적용, 그리고 작업이 완료된 후 스트림을 반드시 닫는 것입니다. Java 7부터는 try-with-resources를 통해 이를 수행하는 것이 좋습니다.
파일을 읽고 쓰는 코드 예시:
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { String line; while ((line = reader.readLine()) != null) { writer.write(line); writer.newLine(); } }
주요 특징:
Java에서 I/O 스트림을 닫지 않으면 어떻게 되나요?
스트림은 OS의 저수준 리소스를 다루며, 스트림을 닫지 않으면 메모리 누수, 파일 잠금, 애플리케이션 오류 또는 심지어 OS 수준의 파일 디스크립터 고갈로 이어질 수 있습니다.
같은 OutputStream을 사용하여 다른 파일에 쓸 수 있나요?
아니요, 클래식 OutputStream은 하나의 데이터 출처/수신기와 강하게 연관되어 있습니다. 다른 파일에 대해서는 서로 다른 OutputStream 객체를 사용해야 합니다.
PrintWriter와 BufferedWriter의 차이는 무엇인가요? 그리고 언제 어떤 것을 사용하나요?
PrintWriter는 println()과 같은 포맷화된 출력 메서드를 추가하는 것에 특화되어 있으며, 자동 플러시 기능을 가지고 있습니다. 반면 BufferedWriter는 주로 버퍼링을 통해 성능을 향상시킵니다. 일반적인 애플리케이션 작업에서는 텍스트 출력을 위해 PrintWriter가 더 선호되지만, 포맷 없이 문자나 문자열을 빠르게 쓰려면 BufferedWriter가 더 적합합니다.
개발자가 FileInputStream을 사용하여 큰 파일에서 데이터를 읽으며 버퍼링을 사용하지 않고 스트림을 닫는 것을 잊습니다.
장점:
단점:
BufferedReader와 try-with-resources 조합을 사용하여 문자열 단위로 패키지로 읽고 처리하며, 스트림이 자동으로 닫힙니다.
장점:
단점: