Java 와 인코딩(webmua의 mbox 파일 처리를 중심으로)
1. mbox 파일은 iso-8859-1 로 읽어야 한다.
encoding 을 알지 못하는 파일을 String으로 읽었다가 다시 byte array 를 거쳐 InputStream으로 변경하여 MimeMessage 에 전달할 때는 iso-8859-1 로 읽은 것을 전달해야 한다.
MimeMessage 에서의 처리는 MailParserProcessorImpl.java 파일을 참조한다.
eml ~ mbox 파일내의 한글은 대부분 ms949 혹은 utf-8 로 encoding 이 사용된다. eml 파일은 1개의 encoding 만 사용될 가능성이 높지만, mbox 나 Thunderbird mbox 는 1개의 파일 내에 여러 개의 encoding이 사용될 가능성이 높다.
최근에는 utf-8 이 일반적이지만, ms949 가 빈번하던 시절도 있었다. 이론적으로 다른 한글 인코딩이 사용될 수도 있을 것이고, 드물지만 utf-8 이나 ms949 호환도 아닌 encoding 이 발견되는 경우도 있다.
2. 어떻게 iso-8859-1 로 읽어야 하나?
Java 는 encoding 을 지정하는 방법이 숨겨져 있는 것처럼 보이지만, 이는 널리 사용되는 메소드들이 시스템의 기본값을 사용하기 때문이다.
전체 소스는 MailMigrationProcessorImpl.java 파일을 참조한다.
2.1. 시스템 기본값
시스템의 기본값을 확인하기 위해서는 다음과 같이 한다.
System.getProperty("file.encoding");
이 값은 Java 프로그램을 실행시킬 때 "-Dfile.encoding=iso-8859-1" 와 같은 명령행 파라미터을 추가해서 지정할 수 있고, 이것이 누락된 경우 Java 프로그램 실행 당시의 locale 을 사용한다.
Linux/Unix 계열에서 locale 을 확인하기 위한 명령어는 다음과 같다.
locale
영향을 미치는 것은 LANG 이라는 항목이고, LANG=C 는 file.encoding=iso-8859-1 이다.
Graha ~ 그 응용프로그램과 같이 WAS 에서 구동되는 프로그램은 시스템 기본값을 변경하지 않고, 프로그램내에서 처리하는 것이 원칙이다.
2.3. eml 파일
eml 파일은 다음과 같이 특별한 처리가 없어도 된다.
FileInputStream fis = new FileInputStream(file); MimeMessage mime = new MimeMessage(null, fis); fis.close();
2.4. mbox 나 Thunderbird mbox 파일
mbox 나 Thunderbird mbox 파일은 여러 개의 이메일로 구성되기 때문에, 이메일을 1개씩 읽어 처리해야 한다.
이메일은 "From - " 으로 시작(Thunderbird mbox) 하거나 "From " 으로 시작(mbox) 하므로, readLine 메소드를 지원하는 BufferedReader 로 처리해야 한다.
BufferedReader 는 charset 을 파라미터로 받는 생성자가 없지만, 생성자의 파라미터인 Reader 를 구현한 InputStreamReader 가 charset 을 파라미터로 받는 생성자를 지원한다.
실제 코드는 예외처리와 다른 처리를 위해 복잡하겠지만, 요약하면 다음과 같다.
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.ISO_8859_1); BufferedReader in = new BufferedReader(isr); String line = null; while ((line = in.readLine()) != null) { } in.close(); isr.close();
이걸로 끝은 아니다.
MimeMessage 에 공급할 InputStream 으로 만들기 위해, String 으로 읽은 것을 다시 byte array 로 변경해야 하는데, 다음과 같이 charset을 지정해야 한다.
byte[] buffer = line.getBytes(StandardCharsets.ISO_8859_1);
2.5. zip 파일에서 파일이름
zip 파일에서는 파일이름을 iso-8859-1 로 가져와야 하는데, 다음과 같이 ZipInputStream 의 생성자에 charset 을 공급한다.
FileInputStream fis = new FileInputStream(fileName); ZipInputStream zis = new ZipInputStream(fis, StandardCharsets.ISO_8859_1); while((ZipEntry entry = zis.getNextEntry()) != null) { String fileName = entry.getName(); }
그렇지 않으면 예외가 발생할 가능성이 높아진다.