728x90
java.io 패키지
@2024.04.17
⭐
InputStream(들어오는 데이터) → 프로그램 → outputStream(나가는 데이터)
모든 데이터는 스트림이라는 형태로 추상화(냇가에 물이 흘러가는 형태) 되어 있다.
따라서 어떤 데이터가 들어오든
사용하는 방법은 똑같다.
들어오는 통로와 나가는 통로가 각각 있다(양방향성이 아닌 단방향)
파일에 무언가를 쓴다! → 자바가 아닌 운영체제가 하는 일이다.
주인공과 장식이 나뉘더라
주인공은 근원지와 목적지를 가지고 있는 클래스 → ex) FileInputStream
장식은 어디서 읽겠다는 것은 없고 버퍼를 제공하겠다 → ex) BufferRedaer
- 해당 생성자를 바라봤을 때 생성자에 또 다른 IO를 받기를 원하는 생성자는 장식
- 장식은 기능이 중요하다! (클래스를 끼우고 끼우고)


Java IO
💡
프로그램이 데이터를 읽고 쓰는 것을 의미하며, 다양한 소스에서 데이터를 읽고 쓰는 데 사용되는 라이브러리와 API 집합이다.
- 기능
- 유연성
- 자바 IO가 다양한 유형의 데이터 소스와 대상에 지원
- 파일, 네트워크 연결, 메모리 내 데이터 등에서 데이터를 읽고 쓸 수 있다.
- 프로그래머가 동일한 인터페이스를 사용하여, 다양한 유형의 데이터 처리가 가능
- 확장성
- 새로운 유형의 데이터 소스나 대상을 쉽게 통합할 수 있게 해주며, 사용자 정의 입출력 처리가 가능
- 재사용 가능성
- 입력과 출력에 관련된 클래스와 인터페이스들이 일관되게 설계되어 있어, 한번 작성한 코드를 다양한 상황에서 재사용 할 수 있다.
- 유연성
- 사용 예시
- 프로그램이 텍스트 문서를 읽기
- 인터넷에서 데이터를 다운로드
- 사용자의 키 입력을 받아 처리
Byte 단위 입출력 Stream
💡
데이터를 바이트 단위로 읽고 쓰는 기능 제공한다.
- 바이트 : 컴퓨터 데이터의 가장 기본적인 단위
- 모든 종류의 데이터를 바이트 형태로 표현 가능!
- 주로 이진 데이터를 다룰 때 사용
- 이진 데이터 : 텍스트가 아닌 파일이나 네트워크 데이터 같은 것
- ex) 이미지, 오디오 파일, 비디오 파일 등
- 텍스트 형태로 읽고 쓰는 것이 아닌 바이트 형태로 직접 처리해야 한다.
- 이진 데이터 : 텍스트가 아닌 파일이나 네트워크 데이터 같은 것
InputStream/OutputStream(입출력 스트림)
💡
InputStream은 데이터를 읽는데 사용하며, OutputStream 은 데이터를 쓰는데 사용된다.
- 이들은 추상 클래스로서, 실제 사용 시에는 이들을 상속받아 구현된 여러 하위 클래스를 사용
- 특징
- 데이터를 한 번에 한 바이트씩 처리
- 대량의 데이터를 처리할 때 매우 유용하나 처리 속도가 느리다.
- 버퍼링과 같은 기술을 사용하여 단점을 극복
- 추상 클래스인 InputStream/OutputStream 상속받아 구현된 여러 하위 클래스
- FileInputStream 클래스 🎇
- 파일로부터 바이트 단위로 데이터를 읽는데 사용
- 파일 시스템에 저장된 데이터를 읽을 때 주로 사용되는 클래스
- FileOutputStream 클래스 🎇
- 파일을 바이트 단위로 데이터를 쓰는데 사용
- 파일 시스템에 데이터를 저장할 때 주로 사용되는 클래스
// 파일 불러오기(읽기) => 입력 스트림 FileInputStream in = new FileInputStream("a.txt"); // b.txt 파일에 쓰기 ( 해당 파일이 없으면 자동 생성) => 출력 스트림 FileOutputStream out = new FileOutputStream("b.txt"); int n; byte[] bytes = new byte[1024]; // 1024 바이트 만큼 읽어오기 // in.read(): 파일로부터 한 바이트씩 읽어오며, 끝에 도달하면 -1 반환 // out.write(c) : 읽어온 바이트를 다른 파일에 쓴다. while ((n = in.read(bytes)) != -1) { String str = new String(bytes); System.out.println(str); out.write(bytes); } // 1바이트씩 읽어오기 while ((n = in.read()) != -1) { System.out.println((char) n); out.write(n); // 1바이트씩 b.txt 파일에 쓰기 } out.close(); in.close();
- ByteArrayInputStream 클래스 🎇
- 바이트 배열로부터 데이터를 읽는다.
- 메모리에 저장된 바이트 배열로부터 데이터를 읽을 때 사용된다.
- ByteArrayOutputStream 클래스 🎇
- 바이트 배열에 데이터를 쓴다.
- 메모리 내에서 데이터를 바이트 배열로 만들어 내는데 사용된다.
// 출력할 문자열 String data = "Hello, ByteArray Streams!"; // 문자열을 바이트 배열로 변환하여 ByteArrayOutputStream에 쓰기 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { byteArrayOutputStream.write(data.getBytes()); } catch (IOException e) { e.printStackTrace(); } // ByteArrayOutputStream에 쓰인 데이터를 바이트 배열로 가져오기 byte[] byteArray = byteArrayOutputStream.toByteArray(); // ByteArrayInputStream으로부터 데이터 읽기 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray); // 바이트 배열에서 데이터를 읽어와 문자열로 변환하여 출력 int byteData; StringBuilder result = new StringBuilder(); try { while ((byteData = byteArrayInputStream.read()) != -1) { result.append((char) byteData); } } catch (IOException e) { e.printStackTrace(); } finally { // ByteArrayInputStream, ByteArrayOutputStream 닫기 try { byteArrayOutputStream.close(); byteArrayInputStream.close(); } catch (IOException e) { e.printStackTrace(); } }
- BufferedInputStream 🎀
- 버퍼링을 사용하여 입력 효율을 높인다.
- 데이터의 일정량을 모아두었다가 한 번에 처리
- 여러 번의 작은 읽기 연산보다 더 효율적으로 데이터를 읽을 수 있다.
- BufferedOutputStream class 🎀
- 버퍼링을 사용하여 출력 효율을 높인다.
- 데이터를 일정량 모아두었다가 한 번에 쓰기 연산을 수행
- 여러 번의 작은 쓰기 연산보다 더 효율적으로 데이터를 출력할 수 있다.
// 입력 파일 경로와 출력 파일 경로 String sourceFile = "source.txt"; String destinationFile = "destination.txt"; // 버퍼 크기 설정 int bufferSize = 1024; // 입력 스트림과 출력 스트림 선언 BufferedInputStream bufferedInputStream = null; BufferedOutputStream bufferedOutputStream = null; try { // 입력 파일에 대한 입력 스트림 생성 bufferedInputStream = new BufferedInputStream(new FileInputStream(sourceFile)); // 출력 파일에 대한 출력 스트림 생성 bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destinationFile)); // 파일 복사 byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = bufferedInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, bytesRead); } System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } finally { // 입력 스트림과 출력 스트림 닫기 try { if (bufferedInputStream != null) { bufferedInputStream.close(); } if (bufferedOutputStream != null) { bufferedOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } }
- DataInputStream 🎀
- 기본 데이터 타입을 바이트 스트림으로부터 직접 읽을 수 있게 한다.
- int, long, float 등 타입을 읽을 때 유용하다.
- DataOutputSteam class 🎀
- 기본 데이터 타입을 바이트 스트림으로 쓸 수 있다.
- int, long, float 등의 데이터 타입을 바이트 스트림에 쉽게 쓸 수 있게 해준다.
// 파일에 데이터 쓰기 try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(filePath))) { // 데이터 쓰기 dataOutputStream.writeUTF("Hello, DataOutputStream!"); dataOutputStream.writeInt(123); dataOutputStream.writeDouble(3.14); } catch (IOException e) { e.printStackTrace(); } // 파일에서 데이터 읽기 try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream(filePath))) { // 데이터 읽기 String message = dataInputStream.readUTF(); int intValue = dataInputStream.readInt(); double doubleValue = dataInputStream.readDouble(); // 읽은 데이터 출력 System.out.println("Message: " + message); System.out.println("Int value: " + intValue); System.out.println("Double value: " + doubleValue); } catch (IOException e) { e.printStackTrace(); }
- FileInputStream 클래스 🎇
Char 단위 입출력 Stream
💡
자바에서 텍스트를 처리할 때 사용되는 입출력 방식으로,
문자 데이터를 읽고 쓰는데 최적화되어있으며 주로
텍스트 파일이나 문자열 데이터를 다룰 때 사용
문자 데이터를 읽고 쓰는데 최적화되어있으며 주로
텍스트 파일이나 문자열 데이터를 다룰 때 사용
- 특징
- 문자 단위 데이터 처리
- 문자가 몇 바이트로 구성되었든 간에 문자 하나를 독립적인 단위로 취급
- 인코딩 호환성
- 문자 기반 스트림은 다양한 문자 인코딩을 지원
- 텍스트 중심
- 텍스트 파일/문자열 데이터 처리에 적합
- HTML, XML. JSON 파일 등의 처리에 주로 사용
- 문자 단위 데이터 처리
Reader/Writer(문자 스트림)
💡
추상 클래스로, 문자 데이터의 입력과 출력을 다루며, 여러 하위 클래스를 통해 구체화된다.
- 추상 클래스인 Reader/Writer 상속받아 구현된 여러 하위 클래스
- FileReader 클래스 🎇
- 텍스트 파일로부터 데이터를 읽기 위해 사용
- 파일의 텍스트 내용을 한 문자씩 읽거나, 문자 배열을 통해 한 번에 읽을 수 있다.
- FileWriter 클래스 🎇
- 텍스트 파일에 데이터를 쓰기 위해 사용
- 문자 데이터를 파일에 쓸 수 있으며, 여러 쓰기 메서드를 제공
// 파일에 텍스트 쓰기 try (FileWriter fileWriter = new FileWriter(filePath)) { fileWriter.write("Hello, FileWriter!"); } catch (IOException e) { e.printStackTrace(); } // 파일에서 텍스트 읽기 try (FileReader fileReader = new FileReader(filePath)) { int character; StringBuilder content = new StringBuilder(); while ((character = fileReader.read()) != -1) { content.append((char) character); } System.out.println("File content: " + content); } catch (IOException e) { e.printStackTrace(); }
- StringReader 클래스 🎇
- 문자열로 데이터를 읽는다.
- 문자열 내의 데이터를 순차적으로 읽어 처리하는 데 사용
- StringReader 클래스 🎇
- 문자열로 데이터를 쓴다.
- 내부적으로 문자열 버퍼를 관리하며, 데이터를 문자열 형태로 쉽게 작성 가능
// 문자열 String text = "Hello, StringWriter and StringReader!"; // StringWriter를 사용하여 문자열 쓰기 StringWriter stringWriter = new StringWriter(); try { stringWriter.write(text); } catch (IOException e) { e.printStackTrace(); } // StringWriter로부터 문자열 읽기 StringReader stringReader = new StringReader(stringWriter.toString()); StringBuilder result = new StringBuilder(); try { int character; while ((character = stringReader.read()) != -1) { result.append((char) character); } } catch (IOException e) { e.printStackTrace(); } finally { // StringReader 닫기 stringReader.close(); }
- BufferedReader 클래스 🎀
- 입력 데이터를 버퍼에 저장하여 효율적으로 읽을 수 있게 한다.
- readLine() 메서드를 통해 한 줄씩 읽는 기능이 자주 사용된다.
- BufferedWriter 클래스 🎀
- 데이터를 내부 버퍼에 저장한 후 한 번에 쓰기를 수행
- 여러 번 작은 쓰기 연산보다 효율적이며, 파일 쓰기 작업에 유용
// 입력 파일 경로와 출력 파일 경로 String sourceFile = "source.txt"; String destinationFile = "destination.txt"; // 파일 읽기와 쓰기를 위한 BufferedReader와 BufferedWriter 선언 BufferedReader bufferedReader = null; BufferedWriter bufferedWriter = null; try { // 입력 파일에 대한 BufferedReader 생성 bufferedReader = new BufferedReader(new FileReader(sourceFile)); // 출력 파일에 대한 BufferedWriter 생성 bufferedWriter = new BufferedWriter(new FileWriter(destinationFile)); // 파일에서 한 줄씩 읽어서 출력 파일에 쓰기 String line; while ((line = bufferedReader.readLine()) != null) { bufferedWriter.write(line); bufferedWriter.newLine(); // 새 줄 추가 } System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } finally { // BufferedReader와 BufferedWriter 닫기 try { if (bufferedReader != null) { bufferedReader.close(); } if (bufferedWriter != null) { bufferedWriter.close(); } } catch (IOException e) { e.printStackTrace(); } }
- InputStreamReader 클래스 🎀
- Byte 스트림을 문자 스트림으로 변환하는 데 사용
- 바이트 기반 스트림을 문자 기반 스트림으로 연결하는 다리 역할
- OutputStreamWriter 클래스 🎀
- 문자 스트림을 바이트 스트림으로 변환하는 데 사용
- 문자 기반 데이터를 바이트 기반 스트림으로 쓸 때 필요
// 바이트 스트림과 문자 스트림을 연결할 바이트 입력 스트림과 출력 스트림 생성 InputStream inputStream = null; OutputStream outputStream = null; try { // 바이트 입력 스트림 생성 inputStream = new FileInputStream("input.txt"); // 바이트 입력 스트림을 문자 입력 스트림으로 변환하는 InputStreamReader 생성 InputStreamReader inputStreamReader = new InputStreamReader(inputStream); // 문자 출력 스트림 생성 outputStream = new FileOutputStream("output.txt"); // 문자 출력 스트림을 바이트 출력 스트림으로 변환하는 OutputStreamWriter 생성 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); // 문자를 읽어서 쓰기 int character; while ((character = inputStreamReader.read()) != -1) { outputStreamWriter.write(character); } System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } finally { // 스트림 닫기 try { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } }
- FileReader 클래스 🎇
특수한 IO - System 클래스
💡
표준 입출력, 시스템 속성, 환경 변수 등과 같은 시스템 관련 작업을 수행하는 데 사용되는 클래스
- 표준 입출력 및 오류 출력에 관련된 정적 메서드
- System.in : 표준 입력 스트림
- 주로 콘솔로부터 사용자의 입력을 받는데 사용
- 이 스트림은 InputStream 형태로 제공된다 ⇒ 바이트 단위 입출력 스트림
- System.out : 표준 출력 스트림 🎀
- 콘솔에 데이터를 출력할 수 있다.
- 주로 텍스트 메시지를 사용자에게 표시하는 데 사용
- System.error : 표준 오류 출력 스트림
- 오류 메시지나 경고를 출력하는 데 사용
- PrintStream 클래스의 인스턴스지만 주로 오류 메시지를 다루는데 쓰인다.
- System.err로 출력된 메시지는 System.out으로 출력된 메시지와 별도로 관리되거나,
다른 색상으로 표시되어 오류를 더 쉽게 식별할 수 있다.
try { reader.close(); } catch (IOException e) { System.err.println("리더를 닫는 중 오류가 발생했습니다: " + e.getMessage()); }
- System.in : 표준 입력 스트림
파일 입출력 ( File I/O )
💡
디스크에 저장된 파일에서 데이터를 읽고, 파일에 데이터를 쓸 수 있다.
- 프로그램과 외부 환경 간의 데이터 교환을 가능하게 한다.
- 주의할 점
- 예외 처리
- IOException을 포함한 여러 예외 발생 가능성
- 입출력 작업은 항상 try-catch 블록 내에서 수행
- 리소스 관리
- 파일과의 연결은 시스템 리소스를 사용
- 사용이 끝난 후에는 반드시 리소스를 해제
- 버퍼링
- 큰 데이터를 처리할 때는 버퍼링을 사용하는 게 좋다
- BufferedReader나 BufferedWriter와 같은 클래스를 사용하면 입출력 효율이 높다.
- 예외 처리
- 파일 쓰는 과정
- 파일과의 연결 생성
- FileOutputStream, FileWriter등의 쓰기 클래스를 사용하여 쓸 파일과 연결을 생성
- 데이터 쓰기
- 파일에 데이터를 쓰기 위한 메서드 호출
- 바이트 데이터 또는 문자 데이터를 파일에 쓸 수 있다.
- 리소스 해제
- 파일 쓰기 작업이 완료되면, 파일과의 연결을 닫고 리소스를 해제
- Byte 단위로 파일 입출력하기
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class ByteFileIOExample { public static void main(String[] args) { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("source.jpg"); out = new FileOutputStream("destination.jpg"); int byteData; while ((byteData = in.read()) != -1) { out.write(byteData); } } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- Char 단위로 파일 입출력하기
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CharFileIOExample { public static void main(String[] args) { FileReader reader = null; FileWriter writer = null; try { reader = new FileReader("inputText.txt"); writer = new FileWriter("outputText.txt"); int character; while ((character = reader.read()) != -1) { writer.write(character); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- 파일과의 연결 생성
보조 스트림(Decorative Streams)
💡
데코레이터 패턴의 한 예로, Java IO에서 기본 스트림에 추가적인 기능을 제공하는 스트림
- 기본 스트림 ⇒ 주인공 🎇
- 파일이나 네트워크 소켓과 같은 데이터 소스나 대상과 직접적으로 연결된다.
- 보조 스트림 ⇒ 장식 🎀
- 기본 스트림 위에 덧붙여져서 추가적인 기능을 수행한다.
- 데이터를 필터링하거나, 버퍼링, 문자와 바이트 간의 변환, 객체 직렬화 등 다양한 기능 수행
- 주요 보조 스트림의 종류
- Bufferd Streams (버퍼링 스트림)
- BufferedReader / BufferedWriter
- 텍스트 데이터를 처리할 때 사용
- 내부적으로 버퍼를 사용해 입출력 효율 향상
- BufferedInputStream / BufferedOutputSteam
- 바이트 데이터를 처리할 때 사용
- 버퍼링을 통해 데이터 읽기 및 쓰기 성능 향상
- BufferedReader / BufferedWriter
- Data Streams (데이터 스트림)
- DataInputStream / DataOutputStream
- 바이너리 데이터를 처리할 때 사용
- 기본 자료형의 데이터를 쉽게 읽고 쓸 수 있게 해준다.
- Object Streams (객체 스트림)
- ObjectInputStream / ObjectOutputStream
- 객체의 직렬화와 역 직렬화를 위해 사용
- 객체를 바이트 형태로 변환하거나, 바이트에서 객체로 복원할 수 있다.
- Print Steram (프린트 스트림)
- PrintWriter / PrintStream
- 형식화된 데이터를 출력할 때 사용
- System.out → PrintSteam의 한 예시
- Character Streams to Byte Streams ( 문자 스트림과 바이트 스트림 변환)
- InputStreamReader / OutputStreamWrite
- 바이트 스트림과 문자 스트림 간의 변환을 위해 사
- Bufferd Streams (버퍼링 스트림)
728x90