본문 바로가기

kh정보교육원 JAVA

InputStreamReader/OutputStreamWriter

 

보조 스트림은 직접 외부자원과 연결하는 것이 아니라 기능 향상을 위해 중간에 껴서 사용하는 것이다.

그렇기 때문에 기반스트림이 있어야지만 외부 자원과 연결하여 파일을 입출력 할 수있다.

 

즉, 원론적으로는 바이트 스트림(InputStream, OutputStream) 문자 스트림(FileReader, FileWriter)  으로 입출력 하는 거지만 우리프로그램에서 더 편하게 읽고 쓸 수 있도록 기능 향상을 위해 중간에 보조스트림이 기능을 한다.

 

아래 두가지는 기억해두자

기반 스트림은 매개변수 생성자 안에 자기가 연결하고자 하는 외부자원 대상을 넣는다.

보조 스트림은 말 그대로 "보조"기 때문에 단독 생성이 안 되고 매개변수 생성자로 기반 스트림을 받는다

 

기반 스트림 사용법 

외부자원 --> 기반 스트림 ----> 메모리 

 

 

문자 변환 보조 스트림  :InputStreamReader/OutputStreamWriter

: 바이트로 된 기반 스트림 사용 --> XXXInputStream, XXXOutputStream

 

기반 스트림에서 InputStreamReader/OutputStreamWrite 보조스트림을 통과하고나면 문자타입으로 변환 시켜준다.

소스 스트림이 바이트 기반 스트림이지만 데이터가 문자일 경우 사용한다. Reader와 Writer는 문자 단위로

입출력을 하기 때문에 데이터가 문자인 경우 바이트 기반 스트림보다 편리하게 사용가능하다.

즉, 가지고 있는 기반 스트림은 바이트 스트림이나 InputStreamReader/OutputStreamWriter 사용 시 문자단위로 변환시켜주기 때문에 문자 입출력하듯이 사용가능하다. 

 

**문자 변환 보조스트림 코드 참조**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.kh.chap04_assist.part01_byteToChar.controller;
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class ByteToCharTest {
    // 표준 입출력 : Sustem.in : 키보드와 연결, System.out : 모니터와 연결, System.err : 에러사항에 대한 출력 
    // JVM이 자동으로 제공해주는 스트림으로 new를 이용해서 직접 객체 생성할 필요 없이 
    // 바로 외부자원으로 키보드, 모니터를 선정한 채로 기반으로 인식 
    public void input() {
        // 생성할 때 OS(외부자원)으로부터받아온 byte 스트림을 문자스트림으로 변환
        // 키보드 기반의 바이트 스트림 -> 문자 기반 스트림으로 변환 
        // 보조 스트림 a = new 보조스트림(기반스트림)  보조스트림은 기반스트림이 필요
        InputStreamReader isr = new InputStreamReader(System.in);  // 키보드로부터 들어오는 길이 열림 
        
        // readLine을 사용하기 위해 BufferedReader 추가 
        // 보조스트림 b = new 보조스트림(a) 
        BufferedReader br = new BufferedReader(isr); //System.in byte타입을 Reader타입으로 변환해주는 리더 타입의 매개변수 isr이 전달 되어야 함 
    
        
        try {
            System.out.print("값 입력 : ");
            String value = br.readLine();   // 최종적으로 버퍼드리드 사용하여 읽어옴 
            System.out.println("value = " + value);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();  
                // 최종적으로 연걸 닫아줌 -> 보조스트림을 닫는 close() 호출하면 close()안에서 다시 연결된 기반스트림을 체크해서 close하는 구문이 완성돼 있음 
                // -> 보조 스트림 close 시 연결 된 기반 스트림도 자동 close
                // 표준 입출력 스트림은 직접 만든 객체가 아닌 제공 받는 스트림이므로 닫으면 다시 열 수 없음     
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    public void output() {
        // 모니터 기반의 바이트 스트림 -> 문자 기반 스트림으로 변환   //기반은 outputstream 보조 연결시 문자 단위로 변환되는 것
        // 보조 스트림 a = new 보조 스트림(기반 스트림)   
        OutputStreamWriter isw = new OutputStreamWriter(System.out); //System.out 기반스트림과 연결됐으니 writer 구문이 모니터 콘솔로 출력 됨 
        // 보조 스트림 b = new 보조 스트림(a)
        BufferedWriter bw = new BufferedWriter(isw);
        
        try {
            bw.write("Hello");
            // write : 버퍼에 쌓는다    // 값이 전달될 때 바로 출력이 아니라(inputstream,outputstream제외) 버퍼에 쌓인 후 내보냄 그렇기 때문에 쌓인 걸 flush해줘야 출력 됨 
            // flush : 내보낸다
            // 스트림 close 시 자동 flush 되어서 그동안 문제 없었지만
            // close 하지 않고 출력하기 위해서는 flush 호출 필요 
            bw.flush();    // 열어놓은 상태로 프로그램이 돌아가야 한다면 flush를 중간중간 해줘야 실질적으로 출력 됨 
        } catch (IOException e) {
            e.printStackTrace();
        } /*finally {
            try {
                //bw.close();  
                // => close 호출 시 하단의 System.out.println() 기능하지 못함
                //      연결 된 기반 스트림 System.out 까지 닫혀서 
            } catch (IOException e) {
                e.printStackTrace();
            }
        }*/
        System.out.println("끝~!");
    }
 
}
 
cs

성능 향상 보조 스트림 : BufferedInputStrea / BufferedOutputStream 

: 바이트로 된 스트림 사용 --> XXXInputStream, XXXOutputStream

 

앞에 Buffer가 붙으면 입출력의 성능을 향상시켜준다. ->  입출력을 모아뒀다가 하기 때문에 입출력 횟수를 줄여줌 

-> 느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용하는 경우 사용한다.

입출력 소스와 직접 작업하지 않고 버퍼에 데이터를 모아 한꺼번에 작업을 하여 실행 성능을 향상한다 (입출력 횟수 줄임)

 

기본 타입 입출력 보조 스트림 : DataInputStream, DataOutputStream

: 바이트로 된 스트림 사용 --> XXXInputStream, XXXOutputStream

 

기반 스트림에서 DataInputStream, DataOutputStream 보조스트림을 통과하고나면 기본타입으로 변환 시켜준다.  

데이터를 8가지 기본자료형과 String 참조 자료형 단위로 읽고 쓸 수 있는 "바이트" 기반 "보조" 스트림이다.

단, 입력된 자료형의 순서와 출력될 자료형의 순서 일치해야 한다. 

출력할 때 int, double, char 순으로 write해서 출력을 했다면

읽어올 때도 int, double, char 순으로 읽어와야 알맞은 타입으로 해석할 수 있다. 

 

객체 입출력 보조 스트림 : ObjectInputStream/ObjectOutputStream

: 객체를 파일 또는 네트워크로 입출력 할 수 있는 기능 

 

기반 스트림에서 ObjectInputStream/ObjectOutputStream 보조스트림을 통과하고나면

바이트 단위로 바꿔서 프로그램 안에 있는 객체 단위별로 입출력이 가능해진다.

 

ObjectOutputStream 객체를 출력 하기 위해서는 직렬화처리가 필요하다.

직렬화 : 객체를 바위트 단위 데이터로 바꿔준다.

직렬화 방법 : 객체화할 클래스에 implements Serialiezble 표시하기

--> Serializable 인터페이스를 implements하여 구현

역직렬화 : 바이트로 들어온 값을 객체로 만드는 것 

 

직렬화 할 때 데이터 모양과, 역직렬화 할 때 정의된 데이터들이 같아야 해석할 수 있다. 

예를들어 Student 클래스를 정의해놓고 이름, 나이를 관리하기로 필드값을 정해 놓았는데,

이름이랑 성적을 관리한다고 바꾸면 직렬화 해서 출력해 놓았던 값을 읽어왔을 때 바뀌었기 때문에

(serialVersion UID 달라짐) 읽어오지 못한다. 

그렇기 때문에 명시적으로 출력시 JVM이 자동으로 생성한  serialVersionUID로 같은 클래스임을 알려주는 것이다.

즉, 출력하기 위해 직렬화 할 때 사용한 JVM이 자동으로 생성된 serialVersionUID를 클래스에 명시해두면 읽어올 때 클래스가 수정이 돼도 같은 클래스임을 인식해서 InvalidClassException 오류 발생이 안 된다. 

=> 저장 후 변경해도 잘 읽어올 수 있도록 역직렬화 시 직렬화 했던 클래스라는 걸 알려주는

     serialVersionUID를 명시하기!

 

간단하게 말하면 파일 저장 후 필드값 수정 후에도 역직렬화에 성공하려면 serialVersionUID를 명시해주면 된다.

단, 수정 시 기존 저장되어 있던 값은 버려지고 수정한 값을 읽어왔을 때 매칭되는 값이 없으니 기본값으로 존재한다.