JAVA/JAVA Basic

[ JAVA ] InputStreamReader : 인코딩

IT록흐 2021. 7. 12. 21:56
반응형

 

 

[ JAVA ] 기반 스트림, 보조 스트림

[ JAVA ] 스트림이란? ( 바이트 기반 스트림 , 문자 기반 스트림 ) 스트림(Stream)에 대해서 파헤쳐보자. [ JAVA ] 문자 인코딩(Character Encoding)이란? 인간과 컴퓨터가 대화하려면 어떻게 할까? 인간의 언

lordofkangs.tistory.com

 

지난 포스팅에서 바이트 스트림의

기반스트림과 보조스트림의 개념을

알아보았다.

 

개인적으로

문자스트림에서 가장 중요한 클래스는

InputStreamReader 클래스라 생각한다.

 

Reader 추상클래스는 유니코드 문자를 읽기 위해 존재한다. 그러나 인코딩에는 다양한 방식이 존재한다. 인코딩의 종류마다 문자를 표현하는 바이트 수도 다르다. UTF-8 인코딩은 한글을 3byte로 표현하고 UTF-16은 한글을 2byte로 표현한다. JVM은 문자를 UTF-16 인코딩 방식으로 메모리에 저장하므로 문자를 2byte(char형)으로 저장한다.

 

 

 

 

고로, 입력된 스트림 데이터는 어떤 인코딩 방식이든 이를 다시 UTF-16 방식으로 인코딩해야한다. JVM은 UTF-16으로 문자를 다루기 때문이다. 이 과정을 다룰 클래스가 필요한데, 이때 사용되는 클래스가 InputStreamReader 클래스이다. InputStreamReader 클래스를 bridge라고도 부른다. 바이트 기반 스트림으로 들어온 스트림 데이터를 디코딩한 후, 이를 다시 UTF-16으로 인코딩하여 문자를 2byte로 저장할 수 있도록 변환하기 때문이다. 

 

< 방법 >

 

InputStreamReader 객체를 생성할 때,

생성자의 매개변수로

디코딩 방식 지정한다.

 

만약 UTF-8 인코딩 파일이면

UTF-8을 매개변수로 넣어 디코딩한다.

 

< 예시 >

 

test.txt

 

이렇게 한글문자로 쓰여진

텍스트 파일을 만든다.

 

 

텍스트 파일을 저장할때

'UTF-8' 인코딩 방식으로 저장한다.

 

그리고 

test.txt를 복사하는 프로그램 코드를

짜보겠다.

 

 

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		
        // 파일 경로 지정
		File testFile = new File("C:\\Users\\USER\\Desktop\\test.txt"); // 복사할 파일 경로
		File resultFile = new File("C:\\Users\\USER\\Desktop\\result.txt"); // 복사된 파일 경로
        
        // 바이트 기반 스트림 객체 생성
		FileInputStream fis = new FileInputStream(testFile);
		FileOutputStream fos = new FileOutputStream(resultFile);
        
        // InputStreamReader 객체 생성, 디코딩 방식 미지정
        InputStreamReader isr = new InputStreamReader(fis);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        
        // 문자 보조 스트림 객체 생성 
		BufferedReader br = new BufferedReader(isr); 
		BufferedWriter bw = new BufferedWriter(osw);
		String str = null;
        
		//파일 복사
		while((str = br.readLine()) != null) {
			bw.write(str+"\n");
		}
		bw.flush();
		bw.close();
		br.close();
	}

}

 

우선,

InputStreamReader 객체를 생성할 때,

디코딩 방식을 명시하지 않았다.

 

명시하지 않으면

디폴트 인코딩 방식으로 

디코딩 한다. 

 

 

프로젝트 우클릭하여 Properties 탭에 들어가면 

디폴트 인코딩 방식을 확인할 수 있다.

 

디폴트로 MS949 인코딩방식이 설정되어 있다. 그렇다면 UTF-8 인코딩 파일을 MS949 방식으로 디코딩한 것이다. 그럼, 당연히 복사된 파일은 문자가 깨져있을 것이다. 한번 확인해보자.

 

 

result.txt

 

 

보다시피 잔뜩 깨져있다.

 

한글문자가 UTF-8로 인코딩되어 스트림(Stream)으로 변환 된 후, FileInputStream으로 읽혀서 프로그램 안으로 들어왔다가, InputStreamReader에 의해 MS949방식으로 디코딩되니 당연히 한글 문자는 깨지게 되는 것이다.

 

 

// InputStreamReader 객체 생성, 디코딩 방식 지정
        InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos);

 

 

그렇다면 생성자에 디코딩방식으로 UTF-8을 명시해주자.

 

 

result.txt

 

위와 같이, 이번에는 깨지지 않았다. 

 

 

 


InputStreamReader의 역할은 간단하다.

 

외부에서 들어오는 문자데이터의 인코딩 방식은 다양하다. 그러므로 이를 적절히 디코딩 한 후, UTF-16 방식으로 다시 인코딩하여 2byte의 메모리에 저장해야 한다. 이 과정을 담당하는 것이 InputStreamReader이다. 

 

FileReader와 FileWriter은 일반적으로 문자 기반 스트림이라 알려져있다. 기반 스트림이란 외부에서 스트림을 읽어오는 스트림 객체를 의미한다. 그러나 FileReader는 InputStreamReader를 상속한다.

 

JAVA API 문서

 

그러므로 FileReader가 read()메소드로 스트림을 읽을 때, InputStreamReader의 read() 메소드를 상속받아 사용한다. 그러나 FileReader는 InputStreamReader와 같이, 생성자로 디코딩 방식을 지정할 수 없다. 그러므로 FileReader 객체가 읽어올 파일은  반드시 프로젝트 디폴트 인코딩 방식과 일치해야한다. 일치하지 않으면 문자는 깨진다. FileReader 클래스는 디코딩 방식을 지정할 수 없으니 유의해야한다. 

 

다음 포스팅에서는 메모리 스트림에 대해서 알아보겠다.

 

반응형