/* * Copyright [2013-2014] PayPal Software Foundation * * 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 ml.shifu.guagua.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; /** * Copied from apache common-io source code. */ public final class FileUtils { /** * Instances should NOT be constructed in standard programming. */ private FileUtils() { } /** * The Unix separator character. */ public static final char UNIX_SEPARATOR = '/'; /** * The Windows separator character. */ public static final char WINDOWS_SEPARATOR = '\\'; /** * The system separator character. */ public static final char SYSTEM_SEPARATOR = File.separatorChar; /** * Returns the path to the system temporary directory. * * @return the path to the system temporary directory. * * @since Commons IO 2.0 */ public static String getTempDirectoryPath() { return System.getProperty("java.io.tmpdir"); } /** * Returns a {@link File} representing the system temporary directory. * * @return the system temporary directory. * * @since Commons IO 2.0 */ public static File getTempDirectory() { return new File(getTempDirectoryPath()); } /** * Returns the path to the user's home directory. * * @return the path to the user's home directory. * * @since Commons IO 2.0 */ public static String getUserDirectoryPath() { return System.getProperty("user.home"); } /** * Returns a {@link File} representing the user's home directory. * * @return the user's home directory. * * @since Commons IO 2.0 */ public static File getUserDirectory() { return new File(getUserDirectoryPath()); } // ----------------------------------------------------------------------- /** * Deletes a directory recursively. * * @param directory * directory to delete * @throws IOException * in case deletion is unsuccessful */ public static void deleteDirectory(File directory) throws IOException { if(!directory.exists()) { return; } if(!isSymlink(directory)) { cleanDirectory(directory); } if(!directory.delete()) { String message = "Unable to delete directory " + directory + "."; throw new IOException(message); } } /** * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. * <p> * The difference between File.delete() and this method are: * <ul> * <li>A directory to be deleted does not have to be empty.</li> * <li>No exceptions are thrown when a file or directory cannot be deleted.</li> * </ul> * * @param file * file or directory to delete, can be <code>null</code> * @return <code>true</code> if the file or directory was deleted, otherwise <code>false</code> * * @since Commons IO 1.4 */ public static boolean deleteQuietly(File file) { if(file == null) { return false; } try { if(file.isDirectory()) { cleanDirectory(file); } } catch (Exception ignored) { } try { return file.delete(); } catch (Exception ignored) { return false; } } /** * Cleans a directory without deleting it. * * @param directory * directory to clean * @throws IOException * in case cleaning is unsuccessful */ public static void cleanDirectory(File directory) throws IOException { if(!directory.exists()) { String message = directory + " does not exist"; throw new IllegalArgumentException(message); } if(!directory.isDirectory()) { String message = directory + " is not a directory"; throw new IllegalArgumentException(message); } File[] files = directory.listFiles(); if(files == null) { // null if security restricted throw new IOException("Failed to list contents of " + directory); } IOException exception = null; for(File file: files) { try { forceDelete(file); } catch (IOException ioe) { exception = ioe; } } if(null != exception) { throw exception; } } // ----------------------------------------------------------------------- /** * Deletes a file. If file is a directory, delete it and all sub-directories. * <p> * The difference between File.delete() and this method are: * <ul> * <li>A directory to be deleted does not have to be empty.</li> * <li>You get exceptions when a file or directory cannot be deleted. (java.io.File methods returns a boolean)</li> * </ul> * * @param file * file or directory to delete, must not be <code>null</code> * @throws NullPointerException * if the directory is <code>null</code> * @throws FileNotFoundException * if the file was not found * @throws IOException * in case deletion is unsuccessful */ public static void forceDelete(File file) throws IOException { if(file.isDirectory()) { deleteDirectory(file); } else { boolean filePresent = file.exists(); if(!file.delete()) { if(!filePresent) { throw new FileNotFoundException("File does not exist: " + file); } String message = "Unable to delete file: " + file; throw new IOException(message); } } } /** * Schedules a file to be deleted when JVM exits. * If file is directory delete it and all sub-directories. * * @param file * file or directory to delete, must not be <code>null</code> * @throws NullPointerException * if the file is <code>null</code> * @throws IOException * in case deletion is unsuccessful */ public static void forceDeleteOnExit(File file) throws IOException { if(file.isDirectory()) { deleteDirectoryOnExit(file); } else { file.deleteOnExit(); } } /** * Schedules a directory recursively for deletion on JVM exit. * * @param directory * directory to delete, must not be <code>null</code> * @throws NullPointerException * if the directory is <code>null</code> * @throws IOException * in case deletion is unsuccessful */ private static void deleteDirectoryOnExit(File directory) throws IOException { if(!directory.exists()) { return; } if(!isSymlink(directory)) { cleanDirectoryOnExit(directory); } directory.deleteOnExit(); } /** * Cleans a directory without deleting it. * * @param directory * directory to clean, must not be <code>null</code> * @throws NullPointerException * if the directory is <code>null</code> * @throws IOException * in case cleaning is unsuccessful */ private static void cleanDirectoryOnExit(File directory) throws IOException { if(!directory.exists()) { String message = directory + " does not exist"; throw new IllegalArgumentException(message); } if(!directory.isDirectory()) { String message = directory + " is not a directory"; throw new IllegalArgumentException(message); } File[] files = directory.listFiles(); if(files == null) { // null if security restricted throw new IOException("Failed to list contents of " + directory); } IOException exception = null; for(File file: files) { try { forceDeleteOnExit(file); } catch (IOException ioe) { exception = ioe; } } if(null != exception) { throw exception; } } /** * Determines whether the specified file is a Symbolic Link rather than an actual file. * <p> * Will not return true if there is a Symbolic Link anywhere in the path, only if the specific file is. * * @param file * the file to check * @return true if the file is a Symbolic Link * @throws IOException * if an IO error occurs while checking the file * @since Commons IO 2.0 */ public static boolean isSymlink(File file) throws IOException { if(file == null) { throw new NullPointerException("File must not be null"); } if(isSystemWindows()) { return false; } File fileInCanonicalDir = null; if(file.getParent() == null) { fileInCanonicalDir = file; } else { File canonicalDir = file.getParentFile().getCanonicalFile(); fileInCanonicalDir = new File(canonicalDir, file.getName()); } if(fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) { return false; } else { return true; } } /** * Determines if Windows file system is in use. * * @return true if the system is Windows */ static boolean isSystemWindows() { return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR; } /** * 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 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 { InputStream in = null; try { in = openInputStream(file); return readLines(in, encoding); } finally { if(in != null) { in.close(); } } } /** * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. * The file is always closed. * * @param file * the file to read, must not be <code>null</code> * @return the list of Strings representing each line in the file, never <code>null</code> * @throws IOException * in case of an I/O error * @since Commons IO 1.3 */ public static List<String> readLines(File file) throws IOException { return readLines(file, null); } /** * 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 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 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); } } /** * 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 IOException * if an I/O error occurs * @since Commons IO 1.1 */ public static List<String> readLines(Reader input) throws IOException { BufferedReader reader = new BufferedReader(input); List<String> list = new ArrayList<String>(); String line = reader.readLine(); while(line != null) { list.add(line); line = reader.readLine(); } return list; } /** * Opens a {@link 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 FileInputStream} for the specified file * @throws FileNotFoundException * if the file does not exist * @throws IOException * if the file object is a directory * @throws IOException * 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() == false) { throw new IOException("File '" + file + "' cannot be read"); } } else { throw new FileNotFoundException("File '" + file + "' does not exist"); } return new FileInputStream(file); } }