스트림(Stream)이란 흐르는 시냇물을 뜻하며, 컴퓨터 공학에서 스트림은 연속적인 데이터의 흐름 혹은 데이터 흐름을 형성해 주는 통로를 가라킨다.
즉, 각종 I/O 장치와의 데이터 이동에 사용되는 객체를 의미한다.
InputStreamReader rd = new InputStreamReader(System.in);
// 입력 스트림으로부터 키 입력, c는 입력된 키의 문자 값
int c = rd.read();
파일 및 디렉토리를 나타내고, 파일/디렉토리와 상호작용할 수 있는 다양한 메서드를 제공하는 클래스로 java.io 패키지에 포함되어 있다.
주요 기능으로는 파일/디렉토리의 생성, 삭제, 이름 변경, 조회, 탐색이 있다.
단, 파일에 직접적으로는 정보를 쓰거나 읽어올 수 없기 때문에 파일 입출력 스트림을 이용해야 한다.
데이터를 바이트 단위로 처리하는 스트림이다. 이는 파일, 네트워크 소켓, 메모리 등 다양한 입출력 소스와 데이터를 주고받을 때 사용된다. 바이트 스트림은 문자가 아닌 바이너리 데이터를 다룰 때 주로 사용된다.
바이트 입력을 수행하는 데 필요한 메서드를 정의하는 추상 클래스이다.
객체를 생성하고, 생성된 객체와 바이트 스트림과 연결함으로써 파일을 open 할 수 있다. 또한 다른 장치들과도 바이트 스트림을 연결할 수 있다.
평소에 데이터를 입력할 때 사용했던 System.in 객체 역시 InputStream의 객체 중 하나이다. 사용법은 다음과 같다.
FileInputStream fin = new FileInputStream("{파일 경로}");
바이트 출력을 수행하는데 필요한 메서드를 정의하는 추상 클래스이다.
객체를 생성하고, 생성된 객체와 바이트 스트림과 연결함으로써 파일을 open한다. 또한 다른 장치들과도 바이트 스트림을 연결할 수 있다.
우리가 출력할 때 주로 사용했던 System.out 객체와 System.err 객체가 OuputStream의 객체 중 하나이다.
OutputStream outputStream = new FileOutputStream("output.txt");
FileInputStream fin = new FileInputStream("input.txt");
FileOutputStream fout = new FileOutputStream("output.txt");
자주 운영체제 API가 호출될수록 하드 디스크 장치나 네트워크 장치가 자주 작동하게 되어 시스템의 효율은 나빠지고 프로그램 역시 여러 번 입출력을 진행해야 하므로 입출력의 실행 속도가 떨어진다. 이 경우 버퍼(Buffer)를 가지게 되면 보다 효율적으로 작동할 수 있다.
버퍼란 데이터를 일시적으로 저장하기 위한 메모리이다. 파일 출력 스트림이 파일에 쓸 데이터를 버퍼에 모아 두었다가, 한 번에 운영체제 API를 호출하여 파일에 쓰게 하면, 운영체제의 부담을 줄이고 장치를 구동하는 일이 줄어들게 되어 시스템의 속도나 효율이 올라가게 될 것이다.
버퍼 스트림을 사용하기 위해서는 입출력 스트림에 연결해서 사용해야 한다.
import java.io.*;
public class ByteFileCopy {
String srcFileName;
String destFileName;
ByteFileCopy(String srcFileName, String destFileName) {
this.srcFileName = srcFileName;
this.destFileName = destFileName;
}
void copy() {
FileInputStream fis = null;
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream(srcFileName);
bis = new BufferedInputStream(fis);
fos = new FileOutputStream(destFileName);
bos = new BufferedOutputStream(fos);
int bData;
while (true) {
bData = bis.read();
if (bData == -1)
break;
bos.write(bData);
}
System.out.println("Copy Success");
} catch (FileNotFoundException fnfe) {
System.err.print(fnfe.getMessage());
System.err.print("복사를 취소합니다!");
} catch (IOException ie) {
ie.printStackTrace();
} finally {
try {
if (bis != null) bis.close();
if (fis != null) fis.close();
if (bos != null) bos.close();
if (fos != null) fos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public static void main(String[] args) {
ByteFileCopy bcopy = new ByteFileCopy("input.png", "output.png");
bcopy.copy();
}
}
DataStream은 기본형 데이터를 읽고 쓰는 데 사용된다.
import java.io.*;
public class DataStreamExample {
public static void main(String[] args) {
String filePath = "data.bin";
// 데이터를 파일에 쓰기
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(filePath))) {
dos.writeInt(42); // 정수 쓰기
dos.writeDouble(3.14159); // 실수 쓰기
dos.writeBoolean(true); // 논리값 쓰기
dos.writeUTF("Hello, DataStream!"); // 문자열 쓰기
System.out.println("데이터 쓰기가 완료되었습니다.");
} catch (IOException e) {
System.err.println("데이터 쓰기 중 오류 발생: " + e.getMessage());
}
// 데이터를 파일에서 읽기
try (DataInputStream dis = new DataInputStream(new FileInputStream(filePath))) {
int intValue = dis.readInt(); // 정수 읽기
double doubleValue = dis.readDouble(); // 실수 읽기
boolean booleanValue = dis.readBoolean(); // 논리값 읽기
String stringValue = dis.readUTF(); // 문자열 읽기
System.out.println("읽은 데이터:");
System.out.println("정수: " + intValue);
System.out.println("실수: " + doubleValue);
System.out.println("논리값: " + booleanValue);
System.out.println("문자열: " + stringValue);
} catch (IOException e) {
System.err.println("데이터 읽기 중 오류 발생: " + e.getMessage());
}
}
}
/*
읽은 데이터:
정수: 42
실수: 3.14159
논리값: true
문자열: Hello, DataStream!
*/
오브젝트 스트림은 객체 데이터를 읽고 쓰는 데 사용되는 스트림이다. 이 스트림을 통해 객체를 직렬화(Serialization)하여 파일에 저장하거나 네트워크를 통해 전송할 수 있다.
: 객체 데이터를 파일 또는 출력 스트림에 기록한다.
: 파일 또는 입력 스트림에서 객체 데이터를 읽어온다.
직렬화는 객체의 상태를 연속된 바이트 형태로 변환하여 파일 저장, 네트워크 전송 등에 활용하는 기술이다. 반대로, 역직렬화(Deserialization)은 저장된 바이트 데이터를 다시 객체로 복원하는 과정이다.
import java.io.*;
// 직렬화를 지원하는 클래스
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 클래스 버전 관리용 ID
private String name;
private int age;
// transient 필드는 직렬화에서 제외됨(민감한 데이터이기 때문)
private transient String password;
public Person(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";
}
}
public class ObjectStreamExample {
public static void main(String[] args) {
String filePath = "person.ser";
// 객체 생성
Person person = new Person("Alice", 30, "securePassword");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
// 객체 직렬화 (쓰기)
try {
oos = new ObjectOutputStream(new FileOutputStream(filePath));
oos.writeObject(person);
System.out.println("객체 직렬화 완료: " + person);
} catch (IOException e) {
System.err.println("직렬화 중 오류 발생: " + e.getMessage());
} finally {
// 스트림 닫기
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
System.err.println("ObjectOutputStream 닫기 중 오류 발생: " + e.getMessage());
}
}
}
// 객체 역직렬화 (읽기)
try {
ois = new ObjectInputStream(new FileInputStream(filePath));
Person deserializedPerson = (Person) ois.readObject();
System.out.println("객체 역직렬화 완료: " + deserializedPerson);
} catch (IOException | ClassNotFoundException e) {
System.err.println("역직렬화 중 오류 발생: " + e.getMessage());
} finally {
// 스트림 닫기
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
System.err.println("ObjectInputStream 닫기 중 오류 발생: " + e.getMessage());
}
}
}
}
}
// 객체 직렬화 완료: Person{name='Alice', age=30, password='securePassword'}
// 객체 역직렬화 완료: Person{name='Alice', age=30, password='null'}
명품 JAVA programming - 황기태, 김효수
https://www.youtube.com/사람만이