스트림(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]