Microsoft 社는 2022년 6월 15일 Internet Explorer 11의 지원을 종료했습니다.

file.encoding 이 US-ASCII 에서 UTF-8 파일 이름 처리방법

제목

file.encoding 이 US-ASCII 에서 UTF-8 파일 이름 처리방법

1. 개요

file.encoding 이 US-ASCII 인데, (한글과 같이) US-ASCII 을 벗어나는 문자열을 처리한다면, 파라미터 뿐만 아니라 파일이름도 처리해야 한다.

System.getProperty("file.encoding") 을 출력하면, ANSI_X3.4-1968 와 같은 것일 수도 있지만, java.nio.charset.Charset.forName("US-ASCII").aliases() 를 출력해 보면, ANSI_X3.4-1968 와 US-ASCII 는 같은 것이다.

파라미터는 request.getParameter 와 인코딩(Graha 라이브러리의 처리방법을 중심으로) 을 참조하면 되고, 이 글에서는 파일이름 처리에 대해서만 다루기로 한다.

file.encoding 이 MS-949 이거나 혹은 다른 것이라도 처리방법은 같다.

2. 파일목록을 가져오는 경우

java.io.File.listFiles() 을 이용해서 파일이름을 가져오면 한글은 전부 다 깨진다.

file.encoding 을 변경할 수 없다면, 다음과 같이 DirectoryStream 을 이용해서 한다.

String filePath = "/";
DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(filePath));
for(Path path : stream) {
String fileName = java.net.URLDecoder.decode(path.toUri().toString().substring(path.toUri().toString().lastIndexOf("/") + 1).replace("+", "%2B"), "UTF-8");
}
stream.close();

DirectoryStream 은 명시적으로 close 해야 하고, 만일 이를 누락한다면, 언젠가는 too many open files 에러가 발생하게 된다.

java.io.File 을 대신해서 Files 를 사용해야 하는데, 많이 사용되는 method 는 다음과 같다.

  • Files.exists(path) : 파일이 존재하는지 여부
  • Files.isDirectory(path) : 디렉토리인지 여부
  • Files.isRegularFile(path) : 일반 파일인지 여부
  • Files.size(path) : 파일 크기
  • Files.getLastModifiedTime(path).toMillis() : 최종 수정일시

3. 파일을 가져오는 경우

new java.io.File("한글 이름 파일.pdf") 과 같이 파일을 가져오려고 시도하면, FileNotFoundException 이 발생한다.

유효한 Path 를 얻은 경우에도, new FileInputStream(Path.toFile()) 혹은 Path.toUri().toURL().openStream() 과 같은 방식으로 InputStream 을 얻을수는 없다.

이를 해결하기 위해서는 다음과 같이 처리해야 한다.

Path path = Paths.get(new URI("file://" + basePath + java.io.File.separator + java.net.URLEncoder.encode("한글 이름 파일.pdf", "UTF-8").replaceAll("\\+", "%20")));
if(Files.exists(path)) {
InputStream fis = Files.newInputStream(path);
fis.close();
}

파일이 존재하는지 검사하는 것도 java.io.File.exists() 는 안되고, Files.exists() 를 사용해야 한다.

4. 파일을 저장하는 경우

new java.io.File("한글 이름 파일.pdf") 과 같이 파일을 저장한다면, (Exception 이 발생하지는 않지만) 한글은 모두 깨져서 물음표(?)로 저장된다.

이를 해결하기 위해서는 다음과 같이 처리해야 한다.

URI uri = new URI("file://" + basePath + java.io.File.separator + java.net.URLEncoder.encode("한글 이름 파일.pdf", "UTF-8").replaceAll("\\+", "%20"));
if(fileItem.isInMemory()) {
Files.write(Paths.get(uri), fileItem.get());
} else {
Files.move(((DiskFileItem)fileItem).getStoreLocation().toPath(), Paths.get(uri));
}

fileItem 변수는 Apache Commons FileUpload 의 FileItem 이다.

상황에 따라 Files.newOutputStream(Paths.get(uri)) 혹은 Files.copy() 메소드를 사용해야 한다.

OutputStream 이 필요하다면, 다음과 같이 해야 한다.

Files.newOutputStream(Paths.get(uri));

5. JavaMail API 에서

이메일을 보낼때, 파일이름에 한글이 포함된 첨부파일을 붙여야 한다면, Path 를 파라미터로 받는 생성자를 가진 javax.activation.DataSource 의 구현체가 있어야 한다.

6. "+" 에 대해서

java.net.URLEncoder.encode 는 공백(" ") 을 "+" 로 변환하고, java.net.URLDecoder.decode 는 (반대로) "+" 를 공백(" ") 으로 변환한다.

따라서 java.net.URLEncoder.encode 를 호출한 이후에 "+" 를 "%20" 으로 변경해야 하고, (반대로) java.net.URLDecoder.decode 전에 "+" 를 "%2B" 로 변경해야 한다.

제목

첨부파일