'MalformedInputException'에 해당되는 글 2건

  1. 2008.10.24 MalformedInputException in depth by 지영아빠
  2. 2008.10.21 sun.io.MalformedInputException (1) by 지영아빠
MalformedInputException에 대해서 궁금하신게 많은것 같아 자료를 조금더 보강해 봤습니다. MalformedInputException이 발생하는 것은 encoding에 맞지 않는 byte가 들어왔을때 발생합니다.

 sun.io.MalformedInputException
    at sun.io.ByteToCharUTF8.convert(ByteToCharUTF8.java:262)
    at sun.nio.cs.StreamDecoder$ConverterSD.convertInto(StreamDecoder.java:314)
    at sun.nio.cs.StreamDecoder$ConverterSD.implRead(StreamDecoder.java:364)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:250)
    at java.io.InputStreamReader.read(InputStreamReader.java:212)
    at java.io.BufferedReader.fill(BufferedReader.java:157)
    at java.io.BufferedReader.read1(BufferedReader.java:208)
    at java.io.BufferedReader.read(BufferedReader.java:282)
    at java.io.Reader.read(Reader.java:143)

이런 Exception이 발생한 경우에 ByteToCharUTF8 소스를 찾아보면 다음과 같이 되어있습니다.

소스: ByteToCharUTF8

UTF-8을 예를 들어 설명하겠습니다.

UTF-8은 기존 unicode의 단점인 속도문제를 개선하기 위해서 만들어진 인코딩 방식으로 Unicode에서 정의된 문자를 1~4byte의 가변으로 처리하는 것입니다.

코드 범위
(십육진법)
UTF-16BE 표현
(이진법)
UTF-8 표현
(이진법)
설명
000000-00007F 00000000 0xxxxxxx 0xxxxxxx ASCII와 동일한 범위
000080-0007FF 00000xxx xxxxxxxx 110xxxxx 10xxxxxx 첫 바이트는 110 또는 1110으로 시작하고, 나머지 바이트들은 10으로 시작함
000800-00FFFF xxxxxxxx xxxxxxxx 1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF 110110yy yyxxxxxx 110111xx xxxxxxxx 11110zzz 10zzxxxx 10xxxxxx 10xxxxxx UTF-16 서로게이트 쌍 영역 (yyyy = zzzzz - 1). UTF-8로 표시된 비트 패턴은 실제 코드 포인트와 동일하다.


영어의 경우에는 u0000~u007F영역으로 ASCII와 동일한 값을 갖습니다. 1byte로 표시됩니다. 한글의 경우에는 u0800~uFFFF영역으로 표시되기 때문에 UTF-8에서는 3byte로 표시됩니다.
예를들어 '김' 이란 글자는 UTF-8에서는 EA B9 80으로 표시가 됩니다. 2진수로 변환하면
11101010 10111001 10000000 이렇게 표시됩니다.

아래 소스코드에서 살펴보면, MalformedInputException은 UTF-8형식에 안맞는 byte가 들어왔을때 발생하는 exception입니다.

한글의 경우에는 3byte인 경우만 살펴보면,
 
 if ((byte1 & 0x80) == 0){
outputChar[0] = (char)byte1;
outputSize = 1;
} else if ((byte1 & 0xe0) == 0xc0) {
if (byteOff >= inEnd) {
savedSize = 1;
savedBytes[0] = (byte)byte1;
break;
}
byte2 = input[byteOff++] & 0xff;
if ((byte2 & 0xc0) != 0x80) { ==>
badInputLength = 2;
byteOff += byteOffAdjustment;
throw new MalformedInputException();
}
outputChar[0] = (char)(((byte1 & 0x1f) << 6) | (byte2 & 0x3f));
outputSize = 1;
} else if ((byte1 & 0xf0) == 0xe0){ // 한글
if (byteOff + 1 >= inEnd) {
savedBytes[0] = (byte)byte1;
if (byteOff >= inEnd) {
savedSize = 1;
} else {
savedSize = 2;
savedBytes[1] = (byte)input[byteOff++];
}
break;
}
byte2 = input[byteOff++] & 0xff;
byte3 = input[byteOff++] & 0xff;
if ((byte2 & 0xc0) != 0x80 || (byte3 & 0xc0) != 0x80) {
badInputLength = 3;
byteOff += byteOffAdjustment;
throw new MalformedInputException();
}
outputChar[0] = (char)(((byte1 & 0x0f) << 12)
| ((byte2 & 0x3f) << 6)
| (byte3 & 0x3f));
outputSize = 1;

((byte2 & 0xc0) != 0x80 || (byte3 & 0xc0) != 0x80)  ==> byte2와 byte3가

으로 시작하지 않는 경우에 발생합니다.


첫 바이트가 110으로 시작했지만, 두번째나 세번째 바이트가 10으로 시작하지 않는

경우에 MalformedInputException이 발생합니다.


이 경우에는 input데이터가 이상이 없는지, 혹은 encoding이 잘못되진 않았는지 살펴봐야
하겠습니다.

*참조*
위키피디어 UTF-8
Modified UTF-8
소스: ByteToCharUTF8

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 지영아빠

아래는 AIX에서 발생한 문제입니다. AIX에서 IBM JVM을 사용하다 발생한 문제인데,
에러메시지는 다음과 같았습니다.

sun.io.MalformedInputException
 at sun.io.ByteToCharEUC.convert(ByteToCharEUC.java:194)
 at sun.nio.cs.StreamDecoder$ConverterSD.convertInto(StreamDecoder.java:314)
 at sun.nio.cs.StreamDecoder$ConverterSD.implRead(StreamDecoder.java:364)
 at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:250)
 at java.io.InputStreamReader.read(InputStreamReader.java:212)
 at java.io.BufferedReader.fill(BufferedReader.java:157)
 at java.io.BufferedReader.readLine(BufferedReader.java:320)
 at java.io.BufferedReader.readLine(BufferedReader.java:383)
...

에러 메시지 자체의 의미는 "인코딩에 맞게 바이트를 해석하던 중 이해할 수 없는 바이트를 발견했다" 는 의미입니다.

부연설명을 드리면, 원래 input으로 들어온 파일이 UTF-8이었습니다.
BufferedReader에서 기본 encoding type으로 읽었기 때문에 한글을 처리하다 문제가 생긴 것입니다.


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 지영아빠

티스토리 툴바