/* * Copyright 2011-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.lucene.analysis.kr.utils; import org.apache.lucene.analysis.kr.morph.MorphException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; /** * file utility class * * @author S.M.Lee */ public class FileUtil { private static final Logger log = LoggerFactory.getLogger(FileUtil.class); public static InputStream getResourceFileStream(String filename) { ClassLoader classLoader = FileUtil.class.getClassLoader(); InputStream stream = classLoader.getResourceAsStream(filename); if (stream == null) { stream = ClassLoader.getSystemResourceAsStream(filename); } return stream; } /** * Given a file name for a file that is located somewhere in the application * classpath, return a File object representing the file. * * @param filename The name of the file (relative to the classpath) that is * to be retrieved. * @return A file object representing the requested filename * @throws MorphException Thrown if the classloader can not be found or if * the file can not be found in the classpath. */ public synchronized static File getClassLoaderFile(String filename) throws MorphException { // note that this method is used when initializing logging, // so it must not attempt to log anything. File file = null; ClassLoader loader = FileUtil.class.getClassLoader(); URL url = loader.getResource(filename); if (url == null) { url = ClassLoader.getSystemResource(filename); if (url == null) { throw new MorphException("Unable to find " + filename); } file = toFile(url); } else { file = toFile(url); } if (file == null || !file.exists()) { return null; } return file; } /** * Reads the contents of a file line by line to a List of Strings. * The file is always closed. * * @param file the file to read, must not be <code>null</code> * @param encoding the encoding to use, <code>null</code> means platform default * @return the list of Strings representing each line in the file, never <code>null</code> * @throws java.io.IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException * if the encoding is not supported by the VM * @since Commons IO 1.1 */ public static List<String> readLines(File file, String encoding) throws IOException { if (log.isDebugEnabled()) log.debug("파일 내용을 읽어드립니다. fName=[{}], encoding=[{}]", file, encoding); return Files.readAllLines(Paths.get(file.toURI()), Charset.forName(encoding)); } /** * Reads the contents of a file line by line to a List of Strings. * The file is always closed. * * @param fName the file to read, must not be <code>null</code> * @param encoding the encoding to use, <code>null</code> means platform default * @return the list of Strings representing each line in the file, never <code>null</code> * @throws org.apache.lucene.analysis.kr.morph.MorphException * * @throws java.io.IOException * @throws java.io.UnsupportedEncodingException * if the encoding is not supported by the VM * @since Commons IO 1.1 */ public static List<String> readLines(String fName, String encoding) { if (log.isDebugEnabled()) log.debug("파일 내용을 읽어드립니다. fName=[{}], encoding=[{}]", fName, encoding); try { return FileUtil.readLines(getResourceFileStream(fName), encoding); } catch (Exception e) { log.error("파일 내용을 읽는데 실패했습니다. fName=" + fName, e); throw new RuntimeException(e); } } public static List<String> readLines(String fName, Charset charset) { if (log.isDebugEnabled()) log.debug("파일 내용을 읽어드립니다. fName=[{}], charset=[{}]", fName, charset); try { return FileUtil.readLines(getResourceFileStream(fName), charset); } catch (Exception e) { log.error("파일 내용을 읽는데 실패했습니다. fName=" + fName, e); throw new RuntimeException(e); } } public static Future<List<String>> readLinesAsync(final String fName, final Charset charset) { if (log.isDebugEnabled()) log.debug("파일 내용을 읽어드립니다. fName=[{}], charset=[{}]", fName, charset); FutureTask<List<String>> futureTask = new FutureTask<List<String>>(new Callable<List<String>>() { @Override public List<String> call() throws Exception { InputStream in = getResourceFileStream(fName); try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset))) { List<String> result = new ArrayList<String>(); for (; ; ) { String line = reader.readLine(); if (line == null) break; result.add(line); } return result; } } }); futureTask.run(); return futureTask; } //----------------------------------------------------------------------- /** * Opens a {@link java.io.FileInputStream} for the specified file, providing better * error messages than simply calling <code>new FileInputStream(file)</code>. * <p/> * At the end of the method either the stream will be successfully opened, * or an exception will have been thrown. * <p/> * An exception is thrown if the file does not exist. * An exception is thrown if the file object exists but is a directory. * An exception is thrown if the file exists but cannot be read. * * @param file the file to open for input, must not be <code>null</code> * @return a new {@link java.io.FileInputStream} for the specified file * @throws java.io.FileNotFoundException if the file does not exist * @throws java.io.IOException if the file object is a directory, if the file cannot be read * @since Commons IO 1.3 */ public static FileInputStream openInputStream(File file) throws IOException { if (file.exists()) { if (file.isDirectory()) { throw new IOException("File '" + file + "' exists but is a directory"); } if (!file.canRead()) { throw new IOException("File '" + file + "' cannot be read"); } } else { throw new FileNotFoundException("File '" + file + "' does not exist"); } return new FileInputStream(file); } // readLines //----------------------------------------------------------------------- /** * Get the contents of an <code>InputStream</code> as a list of Strings, * one entry per line, using the default character encoding of the platform. * <p/> * This method buffers the input internally, so there is no need to use a * <code>BufferedInputStream</code>. * * @param input the <code>InputStream</code> to read from, not null * @return the list of Strings, never null * @throws NullPointerException if the input is null * @throws java.io.IOException if an I/O error occurs * @since Commons IO 1.1 */ public static List<String> readLines(InputStream input) throws IOException { InputStreamReader reader = new InputStreamReader(input); return readLines(reader); } /** * Get the contents of an <code>InputStream</code> as a list of Strings, * one entry per line, using the specified character encoding. * <p/> * Character encoding names can be found at * <a href="http://www.iana.org/assignments/character-sets">IANA</a>. * <p/> * This method buffers the input internally, so there is no need to use a * <code>BufferedInputStream</code>. * * @param input the <code>InputStream</code> to read from, not null * @param encoding the encoding to use, null means platform default * @return the list of Strings, never null * @throws NullPointerException if the input is null * @throws java.io.IOException if an I/O error occurs * @since Commons IO 1.1 */ public static List<String> readLines(InputStream input, String encoding) throws IOException { if (encoding == null) { return readLines(input); } else { InputStreamReader reader = new InputStreamReader(input, encoding); return readLines(reader); } } public static List<String> readLines(InputStream input, Charset charset) throws IOException { if (charset == null) { charset = KoreanEnv.UTF8; } InputStreamReader reader = new InputStreamReader(input, charset); return readLines(reader); } /** * Get the contents of a <code>Reader</code> as a list of Strings, * one entry per line. * <p/> * This method buffers the input internally, so there is no need to use a * <code>BufferedReader</code>. * * @param input the <code>Reader</code> to read from, not null * @return the list of Strings, never null * @throws NullPointerException if the input is null * @throws java.io.IOException if an I/O error occurs * @since Commons IO 1.1 */ public static List<String> readLines(Reader input) throws IOException { try (BufferedReader reader = new BufferedReader(input)) { List<String> lines = new ArrayList<String>(1000); String line = null; while ((line = reader.readLine()) != null) { lines.add(line); } return lines; } } /** * Unconditionally close an <code>InputStream</code>. * <p/> * Equivalent to {@link java.io.InputStream#close()}, except any exceptions will be ignored. * This is typically used in finally blocks. * * @param input the InputStream to close, may be null or already closed */ public static void closeQuietly(InputStream input) { try { if (input != null) { input.close(); } } catch (IOException ignored) { } } //----------------------------------------------------------------------- /** * Convert from a <code>URL</code> to a <code>File</code>. * <p/> * From version 1.1 this method will decode the URL. * Syntax such as <code>file:///my%20docs/file.txt</code> will be * correctly decoded to <code>/my docs/file.txt</code>. * * @param url the file URL to convert, <code>null</code> returns <code>null</code> * @return the equivalent <code>File</code> object, or <code>null</code> * if the URL's protocol is not <code>file</code> * @throws IllegalArgumentException if the file is incorrectly encoded */ public static File toFile(URL url) { if (url == null || !url.getProtocol().equals("file")) { return null; } else { String filename = url.getFile().replace('/', File.separatorChar); int pos = 0; while ((pos = filename.indexOf('%', pos)) >= 0) { if (pos + 2 < filename.length()) { String hexStr = filename.substring(pos + 1, pos + 3); char ch = (char) Integer.parseInt(hexStr, 16); filename = filename.substring(0, pos) + ch + filename.substring(pos + 3); } } return new File(filename); } } //----------------------------------------------------------------------- /** * Reads the contents of a file into a String. * The file is always closed. * * @param file the file to read, must not be <code>null</code> * @param encoding the encoding to use, <code>null</code> means platform default * @return the file contents, never <code>null</code> * @throws java.io.IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException * if the encoding is not supported by the VM */ public static String readFileToString(File file, String encoding) throws IOException { InputStream in = null; try { in = openInputStream(file); return StringUtil.toString(in, encoding); } finally { closeQuietly(in); } } public static byte[] readByteFromCurrentJar(String resource) throws MorphException { String jarPath = FileUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); JarResources jar = new JarResources(jarPath); try { return jar.getResource(resource); } catch (Exception e) { throw new MorphException(e.getMessage(), e); } } }