java.io 문자 - accidentlywoo/java GitHub Wiki

java.io 문자


  1. ASCII코드와 한글 인코딩의 관계를 이해하고, 유니코드와 UTF의 개념을 설명할 수 있다.
  2. 문자 스트림의 특징과 관련 클래스들의 계층구조를 이해하고 관련 클래스들을 이용한 문자 입출력을 구현할 수 있다.

캐릭터와 인코딩

프로그램의 수행 결과를 화면에 출력하거나 파일 같은 저장소에 출력함 -> 출력 데이터는 일반적으로 문자열을 사용함

  • 바이너리 데이터 이미지-오디오-비디오-실행 파일

  • 대부분의 데이터 눈으로 판독이 가능한 텍스트로 구성

자바의 입출력 클래스를 잘 이해하고 사용하기 위해서는? -> 인코딩(Encoding)의 개념을 알아야 함

Java 언어는 영미권에서 만들어졌기 때문에 영어로 입출력하는 경우에는 문제가 없음

다른 문자를 사용하는 나라에서 자국의 언어로 입출력하면 문제가 발생할 수 있음

각 나라의 언어를 표현하는 인코딩이 다르기 때문에 문제가 발생함

ASCII코드

a-z(26개),A-Z(26개) : 52개 0-9(10진수 기준 숫자 10개) : 10개 공백,쉼표..(문장 부호 50~60개) : 60개 -> 대략 120개 안팎의 문자가 필요함

7비트(2^7)로 표현된 문자 체계 -> ASCII 문자 코드

ASCII코드는 7비트로 필요한 모든 영문자와 숫자 등을 표현함

7비트+1비트 = 8비트 : 1로 설정된 부분에 유럽에서 사용하는 특수한 형태의 문자를 추가하여 표현함 ->Latin-1

  • Extended ASCII 128~255의 빈 공간을 사용함 우리나라의 한글을 표현할 때도 이 공간을 사용하여 표현함

한글의 표현

초성 : 기본 자음 14개와 겹자음 5개 : 5비트 + 중성 : 기본 모음 10개와 복모음 11개 : 5비트 + 종성 : 기본 자음 14개, 겹자음 2개, 복자음 11개, 받침이 없는 경우 1개 : 5비트 -> 15비트가 있어야 하나의 한글 표현이 가능함

한글 한 글자는 Extend ASCII를 사용하여 빈 공간을 쓰면 표현할 수 있지만, 1바이트로는 표현할 수 없음 --2바이트를 묶어서 한 글자를 표현함--> -> Multi Byte Character Set

  • 영문 첫 비트가 0인 경우 -> 1바이트를 읽어서 영문으로 해석함

  • 한글 첫 비트가 1인 경우 -> 2 바이트를 읽어서 첫 비트를 떼어냄 -> 5 비트씩 나누어 초성, 중성, 종성으로 대응하여 한글로 인식함 -> KSC5601 = EUC-KR = MS949(Window OS)

각 나라별로 자신만의 고유한 언어를 표현하기 위해서 Extended ASCII를 사용함

전 세계의 데이터가 서로 다르게 해석되는 문제가 발생함

-> 국제 표준화 기구에서 표준 인코딩을 제안함

동일한 바이트 데이터라도 어떻게 해석되는가에 따라 전혀 다른 형태로 인식되는 문제가 가장 큼

자바에서의 글자 깨짐 현상은 인코딩과 관련되어 있음

유니코드(Unicode)

IOS(International Organization for Standardization)에서의 표준화 작업 진행

1바이트 기준 ASCII코드 --문제해결--> 2바이트 기준 새로운 인코딩제안

유니코드(Unicode)를 표준으로 채택함

2바이트는 65536개의 공간을 가지고 있음 각 나라별로 자신의 언어가 속하고 있는 고유한 공간을 배정 받음

  • 한글 0xAC00에서 시작함 192128 = 11,172자 만큼의 공간을 차지함 사전의 순서에 입각하여 모든 글자가 차례대로 나열됨 유니코드 2.0이 만들어질 때 모든 한글이 포함됨

한자는 한글의 약 2배 정도의 공간을 배정받음

  • 유니코드 채택의 가장 중요한 Point 전 세계 26개 언어가 모두 포함되어 있음 어떤 나라에서도 같은 데이터를 공유할 수 있음 자료를 공유하는 표준으로 사용할 수 있음

자바는 유니코드를 지원할 수 있도록 내부적으로 사용하는 글자의 크기를 2바이트로 지정함

Unicoe를 사용하여 표현하는 한글 ASCII를 사용하여 표현하는 한글 -> 바이트 데이터는 서로 다름

'가' -> Unicode로 표현 : 0xAC00 -> ASCII데이터로 표현 : 0xB0A1

같은 한글이라 할지라도 어떤 인코딩을 적용했느냐에 따라 전혀 다르게 해석되고 조합됨

UTF-8

유니코드를 사용할 경우 영미권에 속한 나라는 오히려 불편을 감수해야 하는 상황 발생

ASCII를 기준으로 파일 생성 및 저장 -> 한 문자당 1바이트가 지장됨 Unicoe를 기준으로 파일 생성 및 저장 -> 한 문자 당 2바이트가 지정됨

--데이터 공간이 두 배 이상 필요함, 낭비를 없애기 위해 제안한 해석 방법--> UTF-8

UTF-8은 가변 길이를 지원하는데 각 언어별로 최적화된 크기로 저장할 수 있도록 1바이트에서 3바이트까지 표현이 달라짐 영문의 경우 1바이트로 표현됨 한글의 경우 3바이트로 표현됨

Multi Byte Character Set : 2 바이트 Unicoe : 2바이트 UTF-8 : 3바이트 -> 데이터 표현이 다르기 때문에 다른 바이트 값을 가짐

바이트 데이트의 값과 그 값이 해석된 인코딩이 서로 맞아 떨어질 때 정확한 글자가 나타남

자바에서 인코딩이 적용되는 부분은 어디일까?

바이트 데이터를 기준으로 문자를 만들어 내는 부분 --인코딩 적용--> char와 String 클래스 / 바이트 스트임에서 문자 스트림으로 변환되는 클래스

String과 인코딩

String 클래스의 생성자를 보면 바이트 배열을 어떤 인코딩으로 해석하여 문자를 생성할 것인지 지정하는 생성자가 존재함 <-> 기존의 String 객체를 어떤 인코딩을 통하여 바이트 배열로 분해할 것인지를 지정해서 실행하는 getBytes() 메서드도 존재함

자바에서 글자가 깨지는 현상이 발생한다면?

깨진 글자를 getBytes()로 분해했다가 새롭게 String 객체를 만들어 출력하는 방법으로 해결 다양한 인코딩을 시도해 볼 필요가 있음

문자 스트림

문자 스트림 계층 구조

문자 스트림은 16비트 문자열들을 읽고 쓰기 위한 스트림 모두 Read/Writer의 자식 클래스임 문자 입출력 스트림은 영어 이외의 문자에 대한 처리와 문자 인코딩을 내부에서 처리해 줌 유니코드를 지원하는 자바 특성에 맞게 2바이트 크기의 입출력을 함

문자 스트림을 통해 특별한 문자 인코딩에 독립적인 프로그램을 작성할 수 있고, 좀 더 효율적으로 구현 가능함

  1. Reader

  2. BufferReader

  3. InputStreamReader

    1. FileReader
  1. Writer

  2. BufferedWriter

  3. OutputStreamWriter

    1. FileWriter

모두 문자 단위로 입출력을 수핸한다는 공통적인 특징이 있음 각 클래스들만의 고유한 기능을 가짐 입출력 장치를 대상으로 직접 입출력을 하거나, 다른 클래스를 대상으로 입출력을 하는 클래스도 존재함 -> 2개 이상의 클래스를 연결한 입출력 스트림을 생성해서 입출력을 하는 경우가 일반적임

Reader / Writer

Reader와 Writer는 문자 입출력을 담당하는 추상 클래스임 다른 문자 입출력 클래스들에 대한 최상위 클래스임 Reader와 Writer는 InputStream/OutputStream과 사용법이 유사함

  • Reader 클래스의 메서드 abstract void close() throws IOException : 문자 입력 스트림을 닫음 void mark(int limit) throws IOException : 문자 입력 스트림의 현재 위치를 표시함 int read() throws IOException : 문자 입력 스트림에서 단일 문자를 읽음 int read(char buf[]) throws IOException : 문자 입력 스트림에서 buf[] 크기만큼을 읽어 buf에 저장하고 읽은 문자 수를 반환함

  • Writer 클래스는 문자 스트림을 출력하는 메서드를 제공함 abstract void close() throws IOException : 문자 출력 스트림을 닫음 abstract void flush() throws IOException : 버퍼에 남은 출력 스트림을 출력함 void write(String s) throws IOException : 주어진 문자열 s를 출력함 void write(char buf[]) throws IOException : buf의 내용을 출력함

FileReader / FileWriter

FileReader와 FileWriter는 파일에 저장된 바이트를 유니코드 문자로 변환해서 읽어 들이거나 출력할 유니코드 문자를 디폴트 문자 인코딩의 바이트로 변환해서 파일에 저장하는 데 사용되는 입출력 클래스임

각각 InputStreamReader나 OutputStreamWriter의 자식 클래스로, 유니코드 문자와 바이트 간의 변환 기능을 포함하고 있음

  • FileReader 파일로부터 입력을 위한 스트림을 생성하는 클래스 데이터가 입력될 파일의 정보를 인자로 하는 생성자를 가짐

  • FileReader 의 생성자 FileReader (String filepath) throw FileNotFountException : filepath로 지정한 파일에 대한 입력 스트림을 생성함 FileReader (String fileObj) throw FileNotFountException : fileObj로 지정한 파일에 대한 입력 스트림을 생성함

  • FileWriter 파일로 데이터를 출력하기 위한 출력 스트림을 제공함 출력할 파일에 대한 정보를 인자로 하는 생성자를 가짐

  • FileWriter의 생성자 FileWriter(String filepath) throws IOException : filepath로 지정한 파일에 대한 출력 스트림을 생성함 FileWriter(String filepath, boolean append) throws IOException : 지정한 파일로 출력 스트림을 생성한다. append인자로 출력할 때 파일에 대한 append 모드를 설정함 FileWriter(file fileObj) throws IOException : fileObj로 지정한 파일에 대한 출력 스트림을 생성함

FileWriter 클래스의 객체를 생성할 때 출력할 파일 이름 외에 두 번째 매개변수로 Append 여부를 지정할 수 있음 FileWriter는 Append 설정을 하지 않으면 기본으로 출력 파일에 덮어쓰는 작업을 함 -> 로그 파일과 같이 기존의 데이터를 유지하면서 데이터를 출력하기 위해서는 Append설정을 true값으로 지정해야 함

BufferedReader / BufferedWriter

BufferedInputStream 및 BufferedOutputStream과 동일하게 입출력 스트림에 버퍼 기능을 추가한 문자 스트림임 문자 입력 스트림으로부터 문자를 읽어 들이거나 문자 출력 스트임으로 문자를 내보낼 때 버퍼링을 함으로써 문자, 문자 배열, 문자열 라인 등을 보다 효율적으로 처리할 수 있도록 함 문자 입출력 스트림을 사용하는 경우에는 한 문자씩 읽지만, 버퍼링 기능을 추가하게 되면 입출력 스트림으로부터 미리 버퍼에 데이터를 갖다 놓기 때문에 보다 효율적으로 입출력이 가능함

  • BufferedReader의 생성자 BufferedReader(Reader in) : 주어진 문자 입력 스트림 in에 대해 기본 크기의 버퍼를 갖는 객체를 생성함 BufferedReader(Reader in, int size) : 주어진 문자 입력 스트림 in에 대해 size크기의 버퍼를 갖는 객체를 생성함

  • BufferedReader 메서드 int read() throws IOException : 한 문자를 읽어서 리턴함 int read(char buf[], int off, int len) throws IOException : 문자 입력 스트림에서 len만큼을 읽어 buf[]의 off위치에 저장하고 읽은 문자 수를 반환함 String readLine() : 한 줄을 읽어서 리턴함

  • BufferedWriter의 생성자 BufferedWriter(Writer out) : 주어진 문자 출력 스트림 out에 대해 기본 크기의 버퍼를 갖는 객체를 생성함 BufferedWriter(Writer out, int size) : 주어진 문자 출력 스트림 out에 대해 size크기의 버퍼를 갖는 객체를 생성함

  • BufferedWriter의 메서드 void newLine() throws IOException : 줄 바꿈 void write(char buf[], int off, int len) throws IOException : 주어진 문자 배열 buf[]의 off 위치부터 len만큼의 문자를 출력함 void write(String s, int off, int len) throws IOException : 주어진 문자열 s의 off 위치부터 주어진 길이 len만큼의 문자를 출력함

InputStreamReader / OutputStreamWriter

바이트 스트림에서 문자 스트림으로, 또는 문자 스트림에서 바이트 스트림으로 변환을 제공하는 스트림임

바이트를 읽어서 지정된 문자 인코딩에 따라 문자로 변환하는데 사용함

문자로 변환하는 경우 인코딩 방식은 특정 방식으로 지정할 수도 있고 경우에 따라서 플랫폼의 기본 인코딩을 이용하기도 함

  • InputStreamReader의 생성자 InputStreamReader(InputStream in) : 주어진 입력 바이트 스트림 in에 대해 기본 인코딩을 사용하는 객체를 생성함 InputStreamReader(InputStream in, String enc) : 주어진 입력 바이트 스트림 in에 대해 enc문자 인코딩을 사용하는 객체를 생성함

  • InputStreamReader의 주요 메서드 String getEncoding() : 현재 사용하고 있는 문자 인코딩의 표준 이름을 얻음

  • OutputStreamWriter의 생성자 OutputStreamWriter(OutputStream out) : 주어진 출력 바이트 스트림 out에 대해 기본 인코딩을 사용하는 객체를 생성함 OutputStreamWriter(OutputStream out, String enc) : 주어진 출력 바이트 스트림 out에 대해 enc 문자 인코딩을 사용하는 객체를 생성함

  • OutputStreamWriter의 메서드 String getEncoding() : 현재 사용하고 있는 문자 인코딩의 표준 이름을 얻음

PrintStream / PrintWriter

데이터를 표준 출력하기 위해서 사용하는 스트림 클래스

  • PrintStream System.out.println()의 out객체는 PrintStream 유형의 객체임 자바 1.1부터 PrintStream 클래스가 시스템의 기본 인코딩 방법으로 문자를 바이트로 변환할 수 있도록 개선됨

  • PrintWriter PrintWriter는 문자 스트림으로 유니코드와 로컬 컴퓨터의 문자 인코딩 간의 변환을 처리해 줌 PrintStream보다 PrintWriter를 사용하는 것이 유니코드를 표현하는데 더 효율적 임

  • PrintWriter의 생성자 PrintWriter(OutputStream stream) : OutputStream객체를 인자로 출력 스트림을 생성함 PrintWriter(OutputStream stream, boolean flush) : OutputStream객체를 인자로 출력 스트림을 생성함 flush값이 true면 자동으로 flush() 메서드가 호출됨 PrintWriter(Writer writer) : Writer 객체를 인자로 출력 스트림을 생성함 PrintWriter(Writer write, boolean flush) : Writer객체를 인자로 출력 스트림을 생성함 flush값이 true면 자동으로 flush() 메서드가 호출됨

PrintStream,PrintWriter에 있는 메서드는 다른 스트림과 달리 IOException을 던지지 않음

  • 만약 출력 에러가 발생한다면? 그 사건을 기록하기 위해서 객체 내부에 flag를 설정함 에러가 발생했는지 알기 위해 checkError() 메서드를 사용하여 검사할 수 있음 에러가 발생하면 checkError()메서드는 true를 반환함
sysout("Hello, World");
If (System.out.checkError())

Scanner 클래스

Scanner 클래스는 io패키지에서 제공하는 클래스는 아니지만 표준 입력 스트림으로부터 데이터를 읽어 들일 수 있는 클래스임 Scanner 클래스를 이용하면 키보드 입력 같은 표준 입력 작업을 단순하게 처리할 수 있음