diff --git a/Foundation/org.egovframe.rte.fdl.filehandling/src/main/java/org/egovframe/rte/fdl/filehandling/EgovFileUtil.java b/Foundation/org.egovframe.rte.fdl.filehandling/src/main/java/org/egovframe/rte/fdl/filehandling/EgovFileUtil.java index 41aef2aa..6eab34ca 100755 --- a/Foundation/org.egovframe.rte.fdl.filehandling/src/main/java/org/egovframe/rte/fdl/filehandling/EgovFileUtil.java +++ b/Foundation/org.egovframe.rte.fdl.filehandling/src/main/java/org/egovframe/rte/fdl/filehandling/EgovFileUtil.java @@ -25,6 +25,7 @@ import java.io.*; import java.io.FileNotFoundException; +import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; @@ -146,46 +147,37 @@ public static void cd(final String changDirectory) throws FileSystemException { } /** - * 파일을 읽는다. + * 파일을 플랫폼 기본 문자셋({@link Charset#defaultCharset()})으로 읽는다. + * 인코딩을 지정하려면 {@link #readFile(File, String)}을 사용한다. */ public static String readFile(File file) throws IOException { - BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); String sResult = ""; - try { + try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) { sResult = readFileContent(in); } catch (IllegalArgumentException e) { LOGGER.debug("[{}] EogvFileUtil : {}", e.getClass().getName(), e.getMessage()); - } finally { - in.close(); } return sResult; } /** - * String 형으로 파일의 내용을 읽는다. + * String 형으로 스트림 전체를 읽어 플랫폼 기본 문자셋으로 디코딩한다. */ public static String readFileContent(InputStream in) throws IOException { - StringBuilder buf = new StringBuilder(); - for (int i = in.read(); i != -1; i = in.read()) { - buf.append((char) i); - } - return buf.toString(); + return new String(in.readAllBytes(), Charset.defaultCharset()); } /** - * String 영으로 파일의 내용을 읽는다. + * String 형으로 파일 전체를 읽어 지정한 인코딩으로 디코딩한다. 원본의 개행은 그대로 보존된다. + * encoding이 null이면 플랫폼 기본 문자셋을 사용한다. */ public static String readFile(File file, String encoding) throws IOException { - StringBuilder sb = new StringBuilder(); - List lines = readTextLines(file, encoding); - - for (Iterator it = lines.iterator(); it.hasNext(); ) { - sb.append(it.next()); + Charset charset = encoding == null ? Charset.defaultCharset() : Charset.forName(encoding); + try (InputStream in = new FileInputStream(file)) { + return new String(in.readAllBytes(), charset); } - - return sb.toString(); } /** diff --git a/Foundation/org.egovframe.rte.fdl.filehandling/src/test/java/org/egovframe/rte/fdl/filehandling/FilehandlingServiceTest.java b/Foundation/org.egovframe.rte.fdl.filehandling/src/test/java/org/egovframe/rte/fdl/filehandling/FilehandlingServiceTest.java index 6ce03a01..4048c1f4 100755 --- a/Foundation/org.egovframe.rte.fdl.filehandling/src/test/java/org/egovframe/rte/fdl/filehandling/FilehandlingServiceTest.java +++ b/Foundation/org.egovframe.rte.fdl.filehandling/src/test/java/org/egovframe/rte/fdl/filehandling/FilehandlingServiceTest.java @@ -21,7 +21,9 @@ import java.io.*; import java.net.URL; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.Iterator; import java.util.List; @@ -235,13 +237,126 @@ public void testReadEmptyFile() throws IOException { } /** - * 여러 줄 파일 읽기 테스트. 줄들이 종전과 동일하게 연결되어야 한다. + * 여러 줄 파일 읽기 테스트. 원본의 개행이 보존되어야 한다. */ @Test - public void testReadMultiLineFile() throws IOException { + public void testReadMultiLineFilePreservesLineSeparator() throws IOException { String multiPath = tmppath + "/multiline.txt"; EgovFileUtil.writeFile(multiPath, "line1\nline2\nline3", "UTF-8"); - assertEquals("line1line2line3", EgovFileUtil.readFile(new File(multiPath), "UTF-8")); + assertEquals("line1\nline2\nline3", EgovFileUtil.readFile(new File(multiPath), "UTF-8")); + } + + /** + * 파일 읽기 테스트. 플랫폼 기본 문자셋으로 쓴 한글은 그대로 읽혀야 한다. + */ + @Test + public void testReadFileKoreanWithDefaultCharset() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-default-korean.txt"); + String content = "행정안전부 표준프레임워크"; + + try { + Files.write(file.toPath(), content.getBytes(Charset.defaultCharset())); + + assertEquals(content, EgovFileUtil.readFile(file)); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } + } + + /** + * 빈 파일 읽기 테스트. 내용이 없는 파일은 두 오버로드 모두 빈 문자열을 반환해야 한다. + */ + @Test + public void testReadEmptyFileWithDefaultCharsetAndEncoding() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-empty.txt"); + + try { + Files.write(file.toPath(), new byte[0]); + + assertEquals("", EgovFileUtil.readFile(file)); + assertEquals("", EgovFileUtil.readFile(file, "UTF-8")); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } + } + + /** + * 파일 읽기 테스트. 지정 인코딩으로 읽을 때 LF 개행은 보존되어야 한다. + */ + @Test + public void testReadFileWithEncodingPreservesLf() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-utf8-lf.txt"); + String content = "첫째 줄\n둘째 줄\n셋째 줄\n"; + + try { + Files.write(file.toPath(), content.getBytes(StandardCharsets.UTF_8)); + + assertEquals(content, EgovFileUtil.readFile(file, "UTF-8")); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } + } + + /** + * 파일 읽기 테스트. 지정 인코딩으로 읽을 때 CRLF 개행은 보존되어야 한다. + */ + @Test + public void testReadFileWithEncodingPreservesCrLf() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-utf8-crlf.txt"); + String content = "a\r\nb\r\n"; + + try { + Files.write(file.toPath(), content.getBytes(StandardCharsets.UTF_8)); + + assertEquals(content, EgovFileUtil.readFile(file, "UTF-8")); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } + } + + /** + * 파일 읽기 테스트. EUC-KR로 쓴 파일은 지정 인코딩으로 그대로 읽혀야 한다. + */ + @Test + public void testReadFileWithEucKrEncoding() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-euc-kr.txt"); + String content = "한글\nEUC-KR\n"; + + try { + Files.write(file.toPath(), content.getBytes(Charset.forName("EUC-KR"))); + + assertEquals(content, EgovFileUtil.readFile(file, "EUC-KR")); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } + } + + /** + * 파일 읽기 테스트. 잘못된 UTF-8 바이트 시퀀스는 종전과 같이 대체 문자로 처리되어야 한다. + */ + @Test + public void testReadFileWithInvalidUtf8BytesReplacesMalformedInput() throws IOException { + File file = new File(EgovFileUtil.getTmpDirectory() + "/read-invalid-utf8.txt"); + + try { + Files.write(file.toPath(), new byte[]{(byte) 0xC3, (byte) 0x28}); + + assertEquals("�(", EgovFileUtil.readFile(file, "UTF-8")); + } finally { + if (file.exists()) { + EgovFileUtil.delete(file); + } + } } /**