외부에서 데이터를 읽는 역할을 수행한다.
byte기반의 입력 Stream의 최상위 추상클래스이다.
package home;
import java.io.IOException;
import java.io.InputStream;
public class IOEx1 {
public static void main(String[] args) {
InputStream is = System.in;
int data = -1;
System.out.println("start");
try {
while ((data = is.read()) != -1) {
//대상은 파일이 아니라 콘솔이다.
System.out.println("input : " + (char)data);
}
}catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(is);
}
}
}
→ 위 코드는 InputStream가 byte를 기반으로 하기 때문에 a를 입력하면 제대로 나오지만 "가"를 입력하면 결과가 깨져서 나온다.
package home;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class IOEx1 {
public static void main(String[] args) {
InputStream is = System.in;
InputStreamReader isr = null;
int data = -1;
System.out.println("start");
try {
isr = new InputStreamReader(is);
while ((data = isr.read()) != -1) {
//대상은 파일이 아니라 콘솔이다.
System.out.println("input : " + (char)data);
}
}catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(isr, is);
}
}
}
→ InputStreamReader : byte연산인 InputStream을 InputStreamReader를 통해 char연산으로 변경해준다.
그러면 문자 데이터가 깨지지 않고 잘 나온다.
1) I/O 대상 결정(what)
: 독립적으로 존재 가능하다.
Ex) FileInputStream, FileOutputStream 등 등
2) 가공, 전달(how)
: 필터라고 부른다.
필터란?
Ex) 정수기가 있다면, 정수기 자체는 물이 나오게 하는 것이고, 필터는 깨끗한 물로 바꿔준다.
즉, 바꿔서 다시 내보는 것을 필터라고 한다.
어떤 것을 읽고 쓰는 지를 알아야하므로 독립적으로 존재할 수 없다.
⇒ 1)과 2)는 어떻게 구분할까?
: 생성자의 parameter를 보고 알 수 있다.
1) 의 예시에 FileReader가 있는데
위 사진처럼 다른 Stream을 parameter에 받지 않고 있다.
2) 의 예시에 InputStreamReader가 있는데
위 사진처럼 다른 Stream을 parameter에 받고 있는 것을 알 수 있다.
: 역순으로 닫아줘야 한다.
원래는 읽고 쓰는 것 → 가공하는 것 순서로 있는데 닫을 때는 가공하는 것 → 읽고 쓰는 것으로 해줘야 한다.
⇒ 앞에서부터 닫아버리면 뒤에 의존하고 있는 것들에 영향을 주기에 문제 발생 가능성이 있다.
⇒ 읽기 와 쓰기는 서로 다른 연산이므로 두 연산 사이에는 순서가 존재하지 않는다.
⇒ 연결은 한 대상만 연결한다.
package home;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class IOEx2 {
public static void main(String[] args) {
//byte연산
InputStream is = System.in;
//char연산으로 변경
InputStreamReader isr = null;
//한 줄씩 읽는애(이러면 enter를 빼고 내용만 읽고 여러글자를 읽을 수 있다.)
BufferedReader br = null;
FileWriter fw = null;
//enter 하면 이제 된다
//한줄씩 쓰고 싶어서 println을 쓰고 싶어서 PrintWriter 을 사용한것
PrintWriter pw = null;
//int data = -1;
System.out.println("입력시작");
//ctrl + z : data가 -1로
try {
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
fw = new FileWriter("console.txt");
//이것도 생성자에 넣고 있다.
pw = new PrintWriter(fw);
String line = null;
while ((line = br.readLine()) != null) {
//입력하고 ctrl + z 닫아야 나옴.
//fw.write(line);
pw.println(line);
}
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(pw, fw, br, isr, is);
}
}
}
→ InputStreamReader : byte로 읽은 것을 char로 바꿔서 읽는 것
→ OutputStreamWriter : char로 쓰는 것을 byte로 바꿔서 쓰는 것
⇒ 읽고 쓰는 대상이 서로 반대쪽에 있어서 두 Stream의 방향은 서로 반대방향이다.
→ flush( ) : 강제로 출력 버퍼 안에 있는 것을 빼는 것(버퍼 안에 공간이 있든 말든 내보낸다.)
우리가 파일에 개인정보를 저장했을 때, 그 파일을 열어보면 모두가 개인정보를 볼 수 있다.
but 개인정보를 모두가 볼 수 있는 것이 맞는가?
파일에 개인정보를 저장하되 아무도 볼 수 없도록 해주는 것이 DataInputStream, DataOutputStream 이다.
package home;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyDataStreamEx1 {
public static void save() {
FileOutputStream fos = null;
DataOutputStream dos = null;
try{
fos = new FileOutputStream("some.dat");
dos = new DataOutputStream(fos);
dos.writeInt(3);
dos.writeBoolean(true);
dos.writeDouble(3.14);
dos.writeUTF("하이~");
dos.writeUTF("이것은 예제입니다.");
dos.flush();
}catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(dos,fos);
}
}
public static void load() {
FileInputStream fis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream("some.dat");
dis = new DataInputStream(fis);
while (dis.available() > 0 ) {
int n = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
String str1 = dis.readUTF();
String str2 = dis.readUTF();
System.out.println(n);
System.out.println(b);
System.out.println(d);
System.out.println(str1);
System.out.println(str2);
}
}catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeAll(dis,fis);
}
}
public static void main(String[] args) {
save();
load();
}
}
→ DataStream : 기본 데이터형의 타입별로 읽고 쓰기가 가능하다.
→ writeInt( ), readInt( ) : int 타입
→ writeBoolean( ), readBoolean( ) : boolean 타입
→ writeDouble( ), readDouble( ) : double 타입
→ writeUTF( ), readUTF( ) : String 타입 (기호를 넣어도 된다.)
<save의 결과>
→ 위 사진처럼 글이 깨져서 나오기에 정보를 알 수 없게 된다.
<load의 결과>
→ available( ) : 읽을 수 있는 남은 byte를 읽으라는 의미이다.
→ 우리가 원래 읽던 방식대로 읽지 않은 이유?
: 예를 들어 int 는 4byte씩 읽는데 원래 읽던 방식은 1byte씩 읽기 때문에 하면 안되다.
→ 가장 중요한 점 : 꼭! 쓴 순서대로 읽어야한다!
(쓴 순서대로 읽지 않으면 이상한 값이 출력된다.)
DataStream의 가장 큰 장점
⇒ 데이터를 구분 짓는 일이 힘든데 이러면 데이터를 구분해서 쓰기만 하면 알아서 데이터를 구분해서 해준다.