스트림(Stream) 이란, '데이터의 흐름'을 의미한다.
- 프로그램은 외부에서 데이터를 읽거나 외부로 데이터를 출력하는 작업이 빈번하게 일어나는데, 이때 데이터는 어떠한 통로를 통해서 데이터가 이동된다.
이 통로를Stream이라고 한다.- 다양한 데이터 소스(Collection, Array 등)를 표준화된 방법으로 다루기 위한 것(그 전까지는 List, Set, Map 등의 사용방법이 서로 달랐다.)
자바에는 이러한 기능을 수행하기 위해 InputStream과 OutputStream이 존재하며, 단일 방향으로 연속적으로 흘러간다.
| Java.io 패키지의 주요 클래스 | 설명 |
|---|---|
| File | 파일 시스템의 파일 정보를 얻기 위한 클래스 |
| Console | 콘솔로부터 문자를 입출력하기 위한 클래스 |
| InputStream/OutputStream | byte(바이트) 단위 입출력을 위한 최상위 스트림 클래스 |
| FileInputStream / FileOutputStream | |
| DataInputStream / DataOutputStream | |
| ObjectInputStream / ObjectOutputStream | byte(바이트) 단위 입출력을 위한 하위 스트림 클래스 |
| PrintStream | |
| BufferedInputStream / BufferedOutputStream | |
| Reader / Writer | 문자 단위 입출력을 위한 최상위 입출력 스트림 클래스 |
| FileReader / FileWriter | |
| InputStreamReader / OutputStreamWriter | 문자 단위 입출력을 위한 하위 스트림 클래스 |
| PrintWriter | |
| BufferedReader / BufferedWriter |
- 바이트단위 입출력 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터들을 주고받을 수 있다.
- 문자단위 입출력 스트림 : 오로직 문자만 주고받을 수 있게 특화되어 있다.
바이트 기반 입력 스트림의 최상위 추상 클래스이다.
- 모든 바이트 기반 입력 스트림은 이 클래스를 상속 받는다.
- 파일 데이터를 읽거나 네트워크 소켓을 통해 데이터를 읽거나 키보드에서 입력한 데이터를 읽을 때 사용한다.
- InputStream은 읽기에 대한 다양한 추상 메소드들을 정의해 두어 사용할 수 있다.
- InputStream의 추상메소드를 오버라이딩하여 목적에 따라 데이터를 입력 받을 수 있다.
| Class Name | Type | 객체 생성 | Method |
|---|---|---|---|
| InputStream | byte | InputStream in = System.in; | read() |
| InputStreamReader | char | InputStreamReader reader = new inputStreamReader(in); | read() |
| BufferedReader | String | BufferedReader br = new BufferedReader(reader); | readLine() |
주요 메소드
| 메소드(Method) | 설명 |
|---|---|
| int available() | 현재 읽을 수 있는 바이트 수를 반환한다. |
| void close() | 현재 열려있는 InputStream을 닫는다. |
| void mark(int readlimit) | InputStream에서 현재의 위치를 표시해준다. |
| boolean markSupported() | 해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다. |
| abstract int read() | InputStream에서 한 바이트를 읽어서 int값으로 반환한다. |
| int read(byte[] b) | byte[] b만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수를 반환한다. |
| int read(byte[]b, int off, int len) | len만큼 읽어서 byte[] b의 off위치에 저장하고 읽은 바이트 수를 반환한다. |
| void reset() | mark()를 마지막으로 호출한 위치로 이동한다. |
| long skip(long n) | InputStream에서 n바이트만큼 데이터를 스킵하고 바이트 수를 반환한다. |
바이트 기반 출력 스트림의 최상위 추상 클래스이다.
- 모든 바이트 기반 출력 스트림은 이 클래스를 상속 받는다.
- OutputStream의 추상메소드를 오버라이딩하여 목적에 따라 데이터를 입력 받을 수 있다.
| Class Name | Type | 객체 생성 | Method |
|---|---|---|---|
| OutputStream | byte | OutputStream out = System.out; | write() |
| OutputStreamReader | char | OutputStreamWriter writer = new OutputStreamWriter(out); | write() |
| BufferedWriter | String | BufferedWriter bw = new BufferedWriter(writer); | write() |
주요메소드
| 메소드(Method) | 설명 |
|---|---|
| void close() | OutputStream을 닫는다. |
| void flush() | 버퍼에 남아있는 출력 스트림을 출력한다. |
| void write(byte[] b) | 버퍼의 내용을 출력한다. |
| void write(byte[] b, int off, int len) | b배열 안에 있는 시작 off부터 len만큼 출력한다. |
| abstract void write(int b) | 정수 b의 하위 1바이트를 출력한다. |
java.util.Scanner 보다 성능이 훨씬 좋다.
try {
// System.in : 키보드와 연결된 바이트 스트림
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("입력 >>> ");
String str = br.readLine();
System.out.println(str);
br.close();
} catch(IOException e) {
e.printStackTrace();
}
}
입력 데이터 단위 :
- 1개 :
int- 여러개 :
byte[]
read(byte[] b)
- 읽은 내용은 byte배열 b에 저장시킨다.
- 읽은 바이트 수를 반환한다.
- 읽은 내용이 없다면 -1을 반환한다.
File file = new File("C:\\storage", "b1.bin");
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 파일 생성
fos = new FileOutputStream(file);
// 출력할 데이터 설정
int c = 'A';
String str = "pple Mange 맛있다.";
// java.io.Charset
byte[] b = str.getBytes(StandardCharsets.UTF_8);
// 파일에 정보 생성
fos.write(c);
fos.write(b);
// 여기까지 하면 `C:\\storage` 경로의 b1.bin 파일에 `Apple Mango 맛있다.` 메세지가 담긴채로 생성 된다.
// 바이트 입력 스트림 생성
fis = new FileInputStream(file);
StringBuilder sb = new StringBuilder();
byte[] b = new byte[5]; // 5바이트씩 읽기 위해서 준비
int readByte = 0;
// 읽어오기
while((readByte = fis.read(b)) != -1) { // readByte로 b(5개씩 읽기)를 해서 저장.
sb.append(new String(b, 0, readByte)); // String객체를 생성하면서 offset과 length지정 String으로는 할 수있음.
}
// 문자를 byteStream으로 읽었기 때문에 문제가 발생.
System.out.println(sb.toString()); // Apple Mange 맛있��.
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null) fis.close();
if(fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
출력문 : Apple Mange 맛있��.
위의 코드에서 한글이 깨지게 출력되는게 정상이다.
이 문제를 해결하기 위해서는 문자로 바꿔주는 필터를 껴주면 된다. InputStreamReader
파일 생성하기
// 출력 속도 향상을 위한 BufferedOutputStream , BufferedInputStream
File file = new File("C:\\storage", "b2.bin");
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
// 파일 생성
bos = new BufferedOutputStream(new FileOutputStream(file));
String str = "안녕하세요 반갑습니다.";
byte[] b = str.getBytes("UTF-8");
bos.write(b);
} catch(IOException e ) {
e.printStackTrace();
} finally {
try {
if(bos != null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
파일 읽어오기
File file = new File("C:\\storage", "b2.bin");
FileInputStream fis = null;
InputStreamReader isr = null;
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
// 속도 향상을 하고 싶으면 BufferedReader를 끼울 수 있다.
StringBuilder sb = new StringBuilder();
char[] cbuf = new char[5]; // 5글자씩 읽기 위해서
int readCnt = 0;
while((readCnt = isr.read(cbuf)) != -1) {
sb.append(cbuf, 0, readCnt);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(isr != null) isr.close();
} catch(IOException e) {
e.printStackTrace();
}
}
파일 생성하기
// 변수를 그대로 출력하는 DataOutputStream
File file = new File("C:\\storage", "b3.dat"); // data저장하고있는 dat타입
FileOutputStream fos = null;
DataOutputStream dos = null;
try {
fos = new FileOutputStream(file);
dos = new DataOutputStream(fos);
// 출력할 변수
String name = "에밀리";
int age = 30;
double height = 165.5;
// 출력
dos.writeUTF(name); // "에밀리" 문자 쓰기
dos.writeInt(age); // 30 나이 쓰기
dos.writeDouble(height);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(dos != null) dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
파일 출력하기
// 변수를 그대로 입력 받는 DataInputStream
File file = new File("C:\\storage", "b3.dat");
FileInputStream fis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(file);
dis = new DataInputStream(fis);
String name = dis.readUTF();
int age = dis.readInt();
double height = dis.readDouble();
System.out.println(name + ", " + age + ", " + height);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(dis != null) dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
출력 : 에밀리, 30, 165.5
파일만들기
// 객체를 그대로 출력하는 ObjectOutputStream(보조스트림)
File file = new File("C:\\storage", "b4.dat");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
// 1. User를 3개 저장한 ArrayList
List<User> users = Arrays.asList(
new User(1, "kim", 30),
new User(2, "lee", 40),
new User(3, "choi", 50)
);
// 2. User 1개
User user = new User(4, "min", 60);
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(users);
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(oos != null) oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
파일 출력하기
// 객체를 그대로 입력 받는 ObjectInputStream
File file = new File("C:\\storage", "b4.dat");
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
@SuppressWarnings("unchecked")
List<User> users = (List<User>)ois.readObject();
User user = (User) ois.readObject(); // classcastException
for(User u : users) {
System.out.println(u);
}
System.out.println(user);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(ois != null) ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
출력
User [userNo=1, name=kim, age=30]
User [userNo=2, name=lee, age=40]
User [userNo=3, name=choi, age=50]
User [userNo=4, name=min, age=60]