net.hasor.utils.io.FileUtils Maven / Gradle / Ivy
/*
* Copyright 2008-2009 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 net.hasor.utils.io;
import java.io.*;
import java.util.Collection;
import java.util.List;
/**
* 文件工具
* @version : 2011-6-3
* @author 赵永春 ([email protected])
*/
public abstract class FileUtils {
/**
* Reads the contents of a file into a String.
* The file is always closed.
*
* @param file the file to read, must not be null
* @param encoding the encoding to use, null
means platform default
* @return the file contents, never null
* @throws IOException in case of an I/O error
* @throws 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 IOUtils.toString(in, encoding);
} finally {
IOUtils.closeQuietly(in);
}
}
/**
* Reads the contents of a file into a String using the default encoding for the VM.
* The file is always closed.
*
* @param file the file to read, must not be null
* @return the file contents, never null
* @throws IOException in case of an I/O error
* @since Commons IO 1.3.1
*/
public static String readFileToString(File file) throws IOException {
return readFileToString(file, null);
}
/**
* Reads the contents of a file into a byte array.
* The file is always closed.
*
* @param file the file to read, must not be null
* @return the file contents, never null
* @throws IOException in case of an I/O error
* @since Commons IO 1.1
*/
public static byte[] readFileToByteArray(File file) throws IOException {
InputStream in = null;
try {
in = openInputStream(file);
return IOUtils.toByteArray(in, file.length());
} finally {
IOUtils.closeQuietly(in);
}
}
/**
* 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 null
* @param encoding the encoding to use, null
means platform default
* @return the list of Strings representing each line in the file, never null
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 1.1
*/
public static List readLines(File file, String encoding) throws IOException {
InputStream in = null;
try {
in = openInputStream(file);
return IOUtils.readLines(in, encoding);
} finally {
IOUtils.closeQuietly(in);
}
}
/**
* 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 null
* @return the list of Strings representing each line in the file, never null
* @throws IOException in case of an I/O error
* @since Commons IO 1.3
*/
public static List readLines(File file) throws IOException {
return readLines(file, null);
}
/**
* Returns an Iterator for the lines in a File
.
*
* This method opens an InputStream
for the file.
* When you have finished with the iterator you should close the stream
* to free internal resources. This can be done by calling the
* {@link LineIterator#close()} or
* {@link LineIterator#closeQuietly(LineIterator)} method.
*
* The recommended usage pattern is:
*
* LineIterator it = FileUtils.lineIterator(file, "UTF-8");
* try {
* while (it.hasNext()) {
* String line = it.nextLine();
* /// do something with line
* }
* } finally {
* LineIterator.closeQuietly(iterator);
* }
*
*
* If an exception occurs during the creation of the iterator, the
* underlying stream is closed.
*
* @param file the file to open for input, must not be null
* @param encoding the encoding to use, null
means platform default
* @return an Iterator of the lines in the file, never null
* @throws IOException in case of an I/O error (file closed)
* @since Commons IO 1.2
*/
public static LineIterator lineIterator(File file, String encoding) throws IOException {
InputStream in = null;
try {
in = openInputStream(file);
return IOUtils.lineIterator(in, encoding);
} catch (IOException ex) {
IOUtils.closeQuietly(in);
throw ex;
} catch (RuntimeException ex) {
IOUtils.closeQuietly(in);
throw ex;
}
}
/**
* Returns an Iterator for the lines in a File
using the default encoding for the VM.
*
* @param file the file to open for input, must not be null
* @return an Iterator of the lines in the file, never null
* @throws IOException in case of an I/O error (file closed)
* @since Commons IO 1.3
* @see #lineIterator(File, String)
*/
public static LineIterator lineIterator(File file) throws IOException {
return lineIterator(file, null);
}
//-----------------------------------------------------------------------
/**
* Writes a String to a file creating the file if it does not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, null
means platform default
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
*/
public static void writeStringToFile(File file, String data, String encoding) throws IOException {
writeStringToFile(file, data, encoding, false);
}
/**
* Writes a String to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, null
means platform default
* @param append if true
, then the String will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 2.1
*/
public static void writeStringToFile(File file, String data, String encoding, boolean append) throws IOException {
OutputStream out = null;
try {
out = openOutputStream(file, append);
IOUtils.write(data, out, encoding);
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* Writes a String to a file creating the file if it does not exist using the default encoding for the VM.
*
* @param file the file to write
* @param data the content to write to the file
* @throws IOException in case of an I/O error
*/
public static void writeStringToFile(File file, String data) throws IOException {
writeStringToFile(file, data, null, false);
}
/**
* Writes a String to a file creating the file if it does not exist using the default encoding for the VM.
*
* @param file the file to write
* @param data the content to write to the file
* @param append if true
, then the String will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @since Commons IO 2.1
*/
public static void writeStringToFile(File file, String data, boolean append) throws IOException {
writeStringToFile(file, data, null, append);
}
/**
* Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM.
*
* @param file the file to write
* @param data the content to write to the file
* @throws IOException in case of an I/O error
* @since Commons IO 2.0
*/
public static void write(File file, CharSequence data) throws IOException {
write(file, data, null, false);
}
/**
* Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM.
*
* @param file the file to write
* @param data the content to write to the file
* @param append if true
, then the data will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @since Commons IO 2.1
*/
public static void write(File file, CharSequence data, boolean append) throws IOException {
write(file, data, null, append);
}
/**
* Writes a CharSequence to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, null
means platform default
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 2.0
*/
public static void write(File file, CharSequence data, String encoding) throws IOException {
write(file, data, encoding, false);
}
/**
* Writes a CharSequence to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, null
means platform default
* @param append if true
, then the data will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since IO 2.1
*/
public static void write(File file, CharSequence data, String encoding, boolean append) throws IOException {
String str = data == null ? null : data.toString();
writeStringToFile(file, str, encoding, append);
}
/**
* Writes a byte array to a file creating the file if it does not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* @param file the file to write to
* @param data the content to write to the file
* @throws IOException in case of an I/O error
* @since Commons IO 1.1
*/
public static void writeByteArrayToFile(File file, byte[] data) throws IOException {
writeByteArrayToFile(file, data, false);
}
/**
* Writes a byte array to a file creating the file if it does not exist.
*
* @param file the file to write to
* @param data the content to write to the file
* @param append if true
, then bytes will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @since IO 2.1
*/
public static void writeByteArrayToFile(File file, byte[] data, boolean append) throws IOException {
OutputStream out = null;
try {
out = openOutputStream(file, append);
out.write(data);
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The specified character encoding and the default line ending will be used.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* @param file the file to write to
* @param encoding the encoding to use, null
means platform default
* @param lines the lines to write, null
entries produce blank lines
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 1.1
*/
public static void writeLines(File file, String encoding, Collection> lines) throws IOException {
writeLines(file, encoding, lines, null, false);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line, optionally appending.
* The specified character encoding and the default line ending will be used.
*
* @param file the file to write to
* @param encoding the encoding to use, null
means platform default
* @param lines the lines to write, null
entries produce blank lines
* @param append if true
, then the lines will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 2.1
*/
public static void writeLines(File file, String encoding, Collection> lines, boolean append) throws IOException {
writeLines(file, encoding, lines, null, append);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The default VM encoding and the default line ending will be used.
*
* @param file the file to write to
* @param lines the lines to write, null
entries produce blank lines
* @throws IOException in case of an I/O error
* @since Commons IO 1.3
*/
public static void writeLines(File file, Collection> lines) throws IOException {
writeLines(file, null, lines, null, false);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The default VM encoding and the default line ending will be used.
*
* @param file the file to write to
* @param lines the lines to write, null
entries produce blank lines
* @param append if true
, then the lines will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @since Commons IO 2.1
*/
public static void writeLines(File file, Collection> lines, boolean append) throws IOException {
writeLines(file, null, lines, null, append);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The specified character encoding and the line ending will be used.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* @param file the file to write to
* @param encoding the encoding to use, null
means platform default
* @param lines the lines to write, null
entries produce blank lines
* @param lineEnding the line separator to use, null
is system default
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 1.1
*/
public static void writeLines(File file, String encoding, Collection> lines, String lineEnding) throws IOException {
writeLines(file, encoding, lines, lineEnding, false);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The specified character encoding and the line ending will be used.
*
* @param file the file to write to
* @param encoding the encoding to use, null
means platform default
* @param lines the lines to write, null
entries produce blank lines
* @param lineEnding the line separator to use, null
is system default
* @param append if true
, then the lines will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported by the VM
* @since Commons IO 2.1
*/
public static void writeLines(File file, String encoding, Collection> lines, String lineEnding, boolean append) throws IOException {
OutputStream out = null;
try {
out = openOutputStream(file, append);
IOUtils.writeLines(lines, lineEnding, out, encoding);
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The default VM encoding and the specified line ending will be used.
*
* @param file the file to write to
* @param lines the lines to write, null
entries produce blank lines
* @param lineEnding the line separator to use, null
is system default
* @throws IOException in case of an I/O error
* @since Commons IO 1.3
*/
public static void writeLines(File file, Collection> lines, String lineEnding) throws IOException {
writeLines(file, null, lines, lineEnding, false);
}
/**
* Writes the toString()
value of each item in a collection to
* the specified File
line by line.
* The default VM encoding and the specified line ending will be used.
*
* @param file the file to write to
* @param lines the lines to write, null
entries produce blank lines
* @param lineEnding the line separator to use, null
is system default
* @param append if true
, then the lines will be added to the
* end of the file rather than overwriting
* @throws IOException in case of an I/O error
* @since Commons IO 2.1
*/
public static void writeLines(File file, Collection> lines, String lineEnding, boolean append) throws IOException {
writeLines(file, null, lines, lineEnding, append);
}
//-----------------------------------------------------------------------
/**
* Opens a {@link FileInputStream} for the specified file, providing better
* error messages than simply calling new FileInputStream(file)
.
*
* At the end of the method either the stream will be successfully opened,
* or an exception will have been thrown.
*
* 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 null
* @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);
}
//-----------------------------------------------------------------------
/**
* Opens a {@link FileOutputStream} for the specified file, checking and
* creating the parent directory if it does not exist.
*
* At the end of the method either the stream will be successfully opened,
* or an exception will have been thrown.
*
* The parent directory will be created if it does not exist.
* The file will be created if it 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 written to.
* An exception is thrown if the parent directory cannot be created.
*
* @param file the file to open for output, must not be null
* @return a new {@link FileOutputStream} for the specified file
* @throws IOException if the file object is a directory
* @throws IOException if the file cannot be written to
* @throws IOException if a parent directory needs creating but that fails
* @since Commons IO 1.3
*/
public static FileOutputStream openOutputStream(File file) throws IOException {
return openOutputStream(file, false);
}
/**
* Opens a {@link FileOutputStream} for the specified file, checking and
* creating the parent directory if it does not exist.
*
* At the end of the method either the stream will be successfully opened,
* or an exception will have been thrown.
*
* The parent directory will be created if it does not exist.
* The file will be created if it 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 written to.
* An exception is thrown if the parent directory cannot be created.
*
* @param file the file to open for output, must not be null
* @param append if true
, then bytes will be added to the
* end of the file rather than overwriting
* @return a new {@link FileOutputStream} for the specified file
* @throws IOException if the file object is a directory
* @throws IOException if the file cannot be written to
* @throws IOException if a parent directory needs creating but that fails
* @since Commons IO 2.1
*/
public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file + "' exists but is a directory");
}
if (file.canWrite() == false) {
throw new IOException("File '" + file + "' cannot be written to");
}
} else {
File parent = file.getParentFile();
if (parent != null) {
if (!parent.mkdirs() && !parent.isDirectory()) {
throw new IOException("Directory '" + parent + "' could not be created");
}
}
}
return new FileOutputStream(file, append);
}
//-----------------------------------------------------------------------
/**
* 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);
}
}
/**
* 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, never throwing an exception. If file is a directory, delete it and all sub-directories.
*
* The difference between File.delete() and this method are:
*
* - A directory to be deleted does not have to be empty.
* - No exceptions are thrown when a file or directory cannot be deleted.
*
*
* @param file file or directory to delete, can be {@code null}
* @return {@code true} if the file or directory was deleted, otherwise
* {@code false}
*
* @since 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;
}
}
/**
* Schedules a directory recursively for deletion on JVM exit.
*
* @param directory directory to delete, must not be {@code null}
* @throws NullPointerException if the directory is {@code null}
* @throws IOException in case deletion is unsuccessful
*/
private static void deleteDirectoryOnExit(File directory) throws IOException {
if (!directory.exists()) {
return;
}
directory.deleteOnExit();
if (!isSymlink(directory)) {
cleanDirectoryOnExit(directory);
}
}
/**
* Cleans a directory without deleting it.
*
* @param directory directory to clean, must not be {@code null}
* @throws NullPointerException if the directory is {@code null}
* @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.
*
* Will not return true if there is a Symbolic Link anywhere in the path,
* only if the specific file is.
*
* Note: the current implementation always returns {@code false} if the system
* is detected as Windows using {@link FilenameUtils#isSystemWindows()}
*
* @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 2.0
*/
public static boolean isSymlink(File file) throws IOException {
if (file == null) {
throw new NullPointerException("File must not be null");
}
if (FilenameUtils.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;
}
}
/**
* Deletes a file. If file is a directory, delete it and all sub-directories.
*
* The difference between File.delete() and this method are:
*
* - A directory to be deleted does not have to be empty.
* - You get exceptions when a file or directory cannot be deleted.
* (java.io.File methods returns a boolean)
*
*
* @param file file or directory to delete, must not be {@code null}
* @throws NullPointerException if the directory is {@code null}
* @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}
* @throws NullPointerException if the file is {@code null}
* @throws IOException in case deletion is unsuccessful
*/
public static void forceDeleteOnExit(File file) throws IOException {
if (file.isDirectory()) {
deleteDirectoryOnExit(file);
} else {
file.deleteOnExit();
}
}
}