java.io 패키지의 입출력 스트림은 기본 스트림과 필터 스트림으로 분류할 수 있다.
기본 스트림은 외부 데이터에 직접연결이 되는 스트림이고
필터 스트림은 외부 데이터에 직접 연결하는 것이 아니라 기본 스트림에 추가로 사용할 수 있는 스트림이다.
주로 성능을 향상시키는 목적으로 사용되며 생성자를 보면 구분이 가능하다.
생성자 쪽에 매개변수로 다른 스트림을 이용하는 클래스는 필터 스트림이라고 볼 수 있다.
보조스트림
- 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해서 사용
-보조 스트림은 실제 데이터를 주고 받는 스트림이 아니기 때문에 입출력 처리가 불가능
- 기반 스트림을 먼저 생성한 후 이를 이용하여 보조 스트림을 생성
종류
- 입출력성능 (BufferedInputStream / BufferedOutputStream)
- 기본 데이터 타입 출력 (DataInputStream / DataOutputStream)
- 객체 입출력 (ObjectInputStream / ObjectOutputStream)
FileInputStream fis = new FileInputStream("sample.txt"); //기반스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis); //보조스트림 생성
bis.read(); //보조스트림으로부터 데이터 읽어옴
=>한 줄로 한다면
BufferedInputStream bis = new BufferedIntputStream(new FileInputStream("sample.txt"));
성능 향상 보조 스트림
- 느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용하는 경우 사용
- 입출력 소스와 직접 작업하지 않고 버퍼에 데이터를 모아 한꺼번에 작업을 하여 실행 성능을 향상(입출력 횟수 줄임)
-BufferedInputStream/Reader
-BufferedOutputStream/Writer
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter("src/com/greedy/section03/filterstream/testBuffered.txt"));
bw.write("안녕하세요\n");
bw.write("반갑습니다\n");
/* 버퍼를 이용하는 경우 버퍼가 가득 차면 자동으로 내보내기를 하지만
* 버퍼가 가득 차지 않은 상태에서는 강제로 내보내기를 해야 한다.
* 이 때 flush()를 해주면 파일에 기록된다.*/
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
/* close()를 호출하면 내부적으로 flush()를 하고나서 자원을 반납한다. */
if(bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* BufferedReader
* 버퍼에 미리 읽어온 후 한 줄 단위로 읽어들이는 기능을 제공하며
* 기본 스트림보다 성능을 개선시킨다.
* */
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("src/com/greedy/section03/filterstream/testBuffered.txt"));
/* readLine()을 추가로 제공한다.
* 버퍼의 한 줄을 읽어와서 문자열로 반환한다.
* */
String temp;
while((temp = br.readLine()) != null) {
System.out.println(temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
형변환 보조 스트림
- 기본 스트림이 byte 기반 스트림이고, 보조 스트림이 char 기반 스트림인 경우에 사용
- 자바에서는 콘솔이나 키보드 같은 표준 입력 입출력 장치로부터 데이터를 입출력하기위한 스트림을 표준 스트림 형태로 제공하고 있다. System 클래스의 in, out, err가 대상 데이터의 스트림을 의미한다.
- System.in (InputStream) : 콘솔로부터 데이터를 입력 받는다.
- Syste.out (PrintStream) : 콘솔로 데이터를 출력한다.
- System.err (PrintStream) : 콘솔로 데이터를 출력한다.
=> 즉 자주 사용되는 자원에 대해 미리 스트림을 생성해 두었기 때문에 개발자가 별도로 스트림을 생성하지 않아도 된다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- System.in을 InputStreamReader로 변환하여 바이트기반 스트림을 문자 기반 스트림으로 변환 후 버퍼를 이용한 보조스트림과 연결
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
이런 표준 스트림 중 콘솔로부터 읽어오는 기반 스트림이 InputStream인데 Buffer를 이용해서 성능을 향상시키고 싶은 경우에 형변환 보조스트림을 사용할 수 있다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //형변환
try {
System.out.print("문자열 입력 : ");
String value = br.readLine(); //스캐너와 동일
System.out.println("value : " + value);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* 출력을 위한 것도 동일한 방식으로 사용할 수 있다. */
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
try {
bw.write("java oracle jdbc");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
기본 데이터 타입 보조 스트림
- 기본 자료형 별 데이터를 읽고 쓰기 가능하도록 기능을 제공
(단, 입력된 자료형의 순서와 출력될 자료형의 순서는 일치해야함)
- 외부 데이터로부터 읽어오는 데이터를 바이트형으로만 읽어오면 정수, 문자, 문자열 등 여러 데이터 타입을 취급하는 경우 별도로 처리를 해주어야 한다.
Ex) 정수 입력 받아 처리하려면 parsing을 해주어야 한다.
- 데이터 자료형 별로 처리하는 기능을 추가한 보조 스트림을 제공하고 있다. (DataInputStream/DataOutputStream)
/* 데이터형별로 파일에 기록하는 DataOutputStream 인스턴스 생성*/
DataOutputStream dout = null;
try {
dout = new DataOutputStream(new FileOutputStream("src/com/greedy/section03/filterstream/score.txt"));
/* 파일에 자료형별로 기록 */
dout.writeUTF("김영희");
dout.writeInt(95);
dout.writeChar('A');
dout.writeUTF("김철수");
dout.writeInt(87);
dout.writeChar('B');
dout.writeUTF("홍길동");
dout.writeInt(73);
dout.writeChar('C');
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(dout != null) {
try {
dout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* 데이터형 별로 읽어오는 DataInputStream 인스턴스 작성 */
DataInputStream din = null;
try {
din = new DataInputStream(new FileInputStream("src/com/greedy/section03/filterstream/score.txt"));
while(true) {
/* 파일에 기록한 순서대로 읽어들이지 않은 경우 에러 발생 또는 올바르지 않은 값을 읽어온다. */
System.out.println(din.readUTF() + ", " + din.readInt() + ", " + din.readChar());
/* 무한루프로 읽어들이게 되면 파일에 더이상 읽을 것이 없는 경우 EOException을 발생시킨다.
* catch블럭에 EXFException을 핸들링하는 코드를 추가한다. */
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(EOFException e){
System.out.println("파일 읽기를 완료하였습니다.");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(din != null) {
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
객체 입출력 보조 스트림
- 객체 단위로 파일 또는 네트워크로 입출력 할 수 있는 기능
객체 단위로 입출력을 하기 위한 ObjectInputStream/ObjectOutputStream을 살펴보자
MemberDTO 클래스
- 객체로 입출력을 하기 위해서는 반드시 직렬화 처리를 해야 한다.
- 직렬화 대상 클래스에 Serializable 인터페이스만 구현하면 직렬화가 필요한 상황인 경우 해당 인터페이스를 상속 받았을 시 데이터를 직렬화 처리한다.
직렬화
- 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부에서도 사용할 수 있도록 바이트(byte) 형태로 데이터를 변환하는 기술
- Serializable 인터페이스를 implements하여 구현- 반대로 바이트로 변환된 데이터를 다시 객체로 변환하는 기술을 역직렬화라고 한다.
- serialVersionUID 필드 : 직렬화된 클래스와 같은 클래스임을 알려주는 식별자
컴파일 시 JVM이 자동으로 serialVersionUID 정적필드를 추가해주기 때문에 별도로 작성하지 않아도 오류는 나지 않지만 자동 생성시 역직렬화에서 예상하지 못한 InvaliedClassException을 유발할 수 있으므로 명시해줄 것을 권장한다.
Ex) private static final long serialVersionUID = -6433332838482L;
public class MemberDTO implements java.io.Serializable{
private static final long serialVersionUID = 7171399052371122105L;
/* 회원 정보를 관리하기 위한 용도의 DTO 클래스*/
private String id;
private String pwd;
private String name;
private String email;
private int age;
private char gender;
/* 직렬화 대상에서 제외하고 싶은 필드의 경우 transient 키워드를 이용할 수 있다. */
private transient double point;
public MemberDTO() {}
//매개변수생성자 코드생략
//setter/getter 코드생략
//toString() 오버라이딩 코드생략
Application4 클래스
public class Application4 {
public static void main(String[] args) {
MemberDTO[] outputMembers = {
new MemberDTO("user01", "pass01", "김영희", "young777@greedy.com", 25, '여', 1250.7),
new MemberDTO("user02", "pass02", "김철수", "chul999@greedy.com", 27, '남', 1221.6),
new MemberDTO("user03", "pass03", "유관순", "yoo123@greedy.com", 18, '여', 1234.3)
};
ObjectOutputStream objOut = null;
try {
objOut = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("src/com/greedy/section03/filterstream/testObjectStream.txt")));
for(int i = 0; i < outputMembers.length; i++) {
objOut.writeObject(outputMembers[i]);
}
objOut.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(objOut != null) {
try {
objOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* 실행해보면 java.io.NotSerializableException이 발생한다.
* 이는 직렬화 처리를 해주지 않아서 발생하는 에러이다. */
MemberDTO[] inputMembers = new MemberDTO[3];
ObjectInputStream objIn = null;
try {
objIn = new ObjectInputStream(new BufferedInputStream(new FileInputStream("src/com/greedy/section03/filterstream/testObjectStream.txt")));
// /* 읽어온 Object가 해당하는 Class가 없을 경우 ClassNotFoundException이 발생할 수 있다. */
// while(true) {
// System.out.println(objIn.readObject());
for(int i = 0; i < inputMembers.length; i++) {
inputMembers[i] = (MemberDTO) objIn.readObject();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(EOFException e) {
System.out.println("파일을 모두 읽어왔습니다.");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(objIn != null) {
try {
objIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
for(MemberDTO member : inputMembers) {
System.out.println(member);
}
}
'TIL > Java' 카테고리의 다른 글
[Java] 입출력(IO) - 1. 입력스트림, 출력스트림 (0) | 2022.01.13 |
---|---|
[Java] 예외 처리(Exception) - Throws, try-catch, multi-catch, 사용자정의 Exception, try-with-resource, Exception 오버라이딩 (0) | 2022.01.13 |
[Java] 컬렉션(Collection) - 4. Map(HashMap, Properties) (0) | 2022.01.13 |
[Java] 컬렉션(Collection) - 3. Set(HashSet, LinkedHashSet, TreeSet) (0) | 2022.01.13 |
[Java] 컬렉션(Collection) - 2. List(LinkedList), Stack, Queue (0) | 2022.01.13 |