데이터는 사용자로부터 키보드, 마우스 등을 통해 입력될 수 있고, 파일 또는 네트워크를 통해 입력될 수 있다.
프로그램은 외부에서 데이터를 읽거나 외부로 데이터를 출력하는 작업이 빈번하게 일어난다.
이때 데이터는 어떠한 통로를 통해서 데이터가 이동하는데, 이 통로를Stream
이라 한다.자바에는 이러한 기능을 수행하기 위해
InputStream
과OutputStream
이 존재하며, 단일 방향으로 연속적으로 흘러간다.
InputStream
과OutputStream
은 추상 클래스이며, 추상 메소드를 오버라이딩해서 다양한 역할을 수행할 수 있다.
ex. 파일, 네트워크, 메모리 입출력
InputStream
: 외부에서 데이터를 읽는 역할 수행OutputStream
: 외부로 데이터를 출력하는 역할 수행
- 자바에서 기본적으로 제공하는 I/O 기능은
java.io
패키지에서 제공된다.- 파일 시스템의 정보를 얻기 위한 File 클래스와 데이터를 입출력하기 위한 다양한 입출력 스트림 클래스를 제공한다.
주요 클래스 | 설명 |
---|---|
File | 파일 시스템의 파일 정보를 얻기 위한 클래스 |
Console | 콘솔로부터 문자를 입출력하기 위한 클래스 |
InputStream / OutputStream | 바이트 단위 입출력을 위한 최상위 입출력 스트림 클래스 |
FileInputStream / FileOutputStream DataInputStream / DataOutputStream ObjectInputStream / ObjectOutputStream PrintStream BufferedInputStream / BufferedOutputStream | 바이트 단위 입출력을 위한 하위 스트림 |
Reader / Writer | 문자 단위 입출력을 위한 최상위 입출력 스트림 클래스 |
FileReader / FileWriter InputStreamReader / OutputStreamWriter PrinterWriter BufferedReader / BufferedWriter | 문자 단위 입출력을 위한 하위 스트림 클래스 |
메소드 | 설명 |
---|---|
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바이트를 출력 |
메소드 | 설명 |
---|---|
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바이트만큼 데이터를 건너띄고 바이트 수를 반환 |
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[ ]
int read(byte[] b)
- 읽은 내용은 byte 배열 b에 저장
- 읽은 바이트 수를 반환
- 읽은 내용이 없으면 -1 반환
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class Main {
public static void m1() {
File file = new File("C:\\storage", "b1.bin");
FileOutputStream fos = null;
FileInputStream fis = null;
try {
// C:\\storage\\b1.bin 파일과 연결되는 바이트 출력 스트림
fos = new FileOutputStream(file);
// 출력할 데이터 선언
int c = 'A';
String str = "pple Mango 맛있다.";
byte[] b = str.getBytes(StandardCharsets.UTF_8); // str.getBytes("UTF-8")와 동일
// 출력 (파일에 정보 생성)
fos.write(c);
fos.write(b);
// 여기까지 하면 C:\\storage 폴더의 b1.bin 파일에 "Apple Mango 맛있다." 메세지가 생성 된다.
try {
// 바이트 입력 스트림 생성
fis = new FileInputStream(file);
// 모든 정보를 StringBuilder에 저장한 뒤 확인
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());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null) fis.close();
if(fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Apple Mango 맛있��.
한글이 깨져서 출력되는게 정상이다.
이것을 해결하기 위해서는 문자로 바꿔주는 InputStreamReader
를 사용하면 된다.
OutputStreamWriter
: 문자 스트림을 바이트 스트림으로 변환InputStreamReader
: 바이트 입력 스트림을 문자 입력 스트림으로 변환파일 생성
- 출력 속도 향상을 위한
BufferedOutputStream
,BufferedInputStream
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void m2() {
// 출력 속도 향상을 위한 BufferedOutputStream
File file = new File("C:\\storage", "b2.bin");
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
// 파일 생성
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
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();
}
}
}
}
파일 읽기
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void m2() {
// 바이트 입력 스트림을 문자 입력 스트림으로 변환하는 InputStreamReader
File file = new File("C:\\storage", "b2.bin");
FileInputStream fis = null;
InputStreamReader isr = null;
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis);
StringBuilder sb = new StringBuilder();
char[] cbuf = new char[5]; // 5글자씩 읽기 위해
int readCnt = 0;
while((readCnt = isr.read(cbuf)) != -1) {
sb.append(cbuf, 0, readCnt);
}
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(isr != null) isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
안녕하세요 반갑습니다.
DataOutputStream
: 변수를 그대로 출력한다.DataInputStream
: 변수를 그대로 입력 받는다.파일 생성
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void m3() {
// 변수를 그대로 출력하는 DataOutputStream
File file = new File("C:\\storage", "b3.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);
dos.writeDouble(height);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(dos != null) dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
파일 읽기
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
public static void m3() {
// 변수를 그대로 입력 받는 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
: 객체를 그대로 출력한다.ObjectInputStream
: 객체를 그대로 입력 받는다.파일 생성
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void m4() {
// 객체를 그대로 출력하는 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();
}
}
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;
public class Main {
public static void m4() {
// 객체를 그대로 입력 받는 ObjectInputStream
File file = new File("C:\\storage", "b4.dat");
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
List<User> users = (List<User>)ois.readObject();
User user = (User)ois.readObject();
for(User u : users) {
System.out.println(u);
}
System.out.println(user);
} catch(ClassNotFoundException e) { // readObject 예외
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]
- 스트림을 이용해서 객체를 전송하려면 직렬화를 해야 한다.
- 직렬화가 필요한 객체는
Serializable
인터페이스를 구현해야 한다.Serializable
인터페이스를 구현한 클래스는SerialVersionUID
필드가 필요하다.
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = -1830845902387248224L;
private int userNo;
private String name;
private int age;
public User(int userNo, String name, int age) {
super();
this.userNo = userNo;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User [userNo=" + userNo + ", name=" + name + ", age=" + age + "]";
}
}