diff options
Diffstat (limited to 'guava/src/com/google/common/io/Files.java')
-rw-r--r-- | guava/src/com/google/common/io/Files.java | 377 |
1 files changed, 94 insertions, 283 deletions
diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java index c3dd506..1d3ce1a 100644 --- a/guava/src/com/google/common/io/Files.java +++ b/guava/src/com/google/common/io/Files.java @@ -16,21 +16,15 @@ package com.google.common.io; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.io.FileWriteMode.APPEND; import com.google.common.annotations.Beta; -import com.google.common.base.Charsets; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableSet; -import com.google.common.hash.HashCode; -import com.google.common.hash.HashFunction; import java.io.BufferedReader; import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; @@ -46,8 +40,8 @@ import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.charset.Charset; +import java.security.MessageDigest; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.zip.Checksum; @@ -57,7 +51,6 @@ import java.util.zip.Checksum; * <p>All method parameters must be non-null unless documented otherwise. * * @author Chris Nokleberg - * @author Colin Decker * @since 1.0 */ @Beta @@ -73,14 +66,11 @@ public final class Files { * character set. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @return the buffered reader */ public static BufferedReader newReader(File file, Charset charset) throws FileNotFoundException { - checkNotNull(file); - checkNotNull(charset); return new BufferedReader( new InputStreamReader(new FileInputStream(file), charset)); } @@ -90,171 +80,16 @@ public final class Files { * character set. * * @param file the file to write to - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @return the buffered writer */ public static BufferedWriter newWriter(File file, Charset charset) throws FileNotFoundException { - checkNotNull(file); - checkNotNull(charset); return new BufferedWriter( new OutputStreamWriter(new FileOutputStream(file), charset)); } /** - * Returns a new {@link ByteSource} for reading bytes from the given file. - * - * @since 14.0 - */ - public static ByteSource asByteSource(File file) { - return new FileByteSource(file); - } - - private static final class FileByteSource extends ByteSource { - - private final File file; - - private FileByteSource(File file) { - this.file = checkNotNull(file); - } - - @Override - public FileInputStream openStream() throws IOException { - return new FileInputStream(file); - } - - @Override - public long size() throws IOException { - if (!file.isFile()) { - throw new FileNotFoundException(file.toString()); - } - return file.length(); - } - - @Override - public byte[] read() throws IOException { - long size = file.length(); - // some special files may return size 0 but have content - // read normally to be sure - if (size == 0) { - return super.read(); - } - - // can't initialize a large enough array - // technically, this could probably be Integer.MAX_VALUE - 5 - if (size > Integer.MAX_VALUE) { - // OOME is what would be thrown if we tried to initialize the array - throw new OutOfMemoryError("file is too large to fit in a byte array: " - + size + " bytes"); - } - - // initialize the array to the current size of the file - byte[] bytes = new byte[(int) size]; - - Closer closer = Closer.create(); - try { - InputStream in = closer.register(openStream()); - int off = 0; - int read = 0; - - // read until we've read size bytes or reached EOF - while (off < size - && ((read = in.read(bytes, off, (int) size - off)) != -1)) { - off += read; - } - - byte[] result = bytes; - - if (off < size) { - // encountered EOF early; truncate the result - result = Arrays.copyOf(bytes, off); - } else if (read != -1) { - // we read size bytes... if the last read didn't return -1, the file got larger - // so we just read the rest normally and then create a new array - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteStreams.copy(in, out); - byte[] moreBytes = out.toByteArray(); - result = new byte[bytes.length + moreBytes.length]; - System.arraycopy(bytes, 0, result, 0, bytes.length); - System.arraycopy(moreBytes, 0, result, bytes.length, moreBytes.length); - } - // normally, off should == size and read should == -1 - // in that case, the array is just returned as is - return result; - } catch (Throwable e) { - throw closer.rethrow(e); - } finally { - closer.close(); - } - } - - @Override - public String toString() { - return "Files.asByteSource(" + file + ")"; - } - } - - /** - * Returns a new {@link ByteSink} for writing bytes to the given file. The - * given {@code modes} control how the file is opened for writing. When no - * mode is provided, the file will be truncated before writing. When the - * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will - * append to the end of the file without truncating it. - * - * @since 14.0 - */ - public static ByteSink asByteSink(File file, FileWriteMode... modes) { - return new FileByteSink(file, modes); - } - - private static final class FileByteSink extends ByteSink { - - private final File file; - private final ImmutableSet<FileWriteMode> modes; - - private FileByteSink(File file, FileWriteMode... modes) { - this.file = checkNotNull(file); - this.modes = ImmutableSet.copyOf(modes); - } - - @Override - public FileOutputStream openStream() throws IOException { - return new FileOutputStream(file, modes.contains(APPEND)); - } - - @Override - public String toString() { - return "Files.asByteSink(" + file + ", " + modes + ")"; - } - } - - /** - * Returns a new {@link CharSource} for reading character data from the given - * file using the given character set. - * - * @since 14.0 - */ - public static CharSource asCharSource(File file, Charset charset) { - return asByteSource(file).asCharSource(charset); - } - - /** - * Returns a new {@link CharSink} for writing character data to the given - * file using the given character set. The given {@code modes} control how - * the file is opened for writing. When no mode is provided, the file - * will be truncated before writing. When the - * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will - * append to the end of the file without truncating it. - * - * @since 14.0 - */ - public static CharSink asCharSink(File file, Charset charset, - FileWriteMode... modes) { - return asByteSink(file, modes).asCharSink(charset); - } - - /** * Returns a factory that will supply instances of {@link FileInputStream} * that read from a file. * @@ -263,7 +98,13 @@ public final class Files { */ public static InputSupplier<FileInputStream> newInputStreamSupplier( final File file) { - return ByteStreams.asInputSupplier(asByteSource(file)); + Preconditions.checkNotNull(file); + return new InputSupplier<FileInputStream>() { + @Override + public FileInputStream getInput() throws IOException { + return new FileInputStream(file); + } + }; } /** @@ -289,13 +130,13 @@ public final class Files { */ public static OutputSupplier<FileOutputStream> newOutputStreamSupplier( final File file, final boolean append) { - return ByteStreams.asOutputSupplier(asByteSink(file, modes(append))); - } - - private static FileWriteMode[] modes(boolean append) { - return append - ? new FileWriteMode[]{ FileWriteMode.APPEND } - : new FileWriteMode[0]; + Preconditions.checkNotNull(file); + return new OutputSupplier<FileOutputStream>() { + @Override + public FileOutputStream getOutput() throws IOException { + return new FileOutputStream(file, append); + } + }; } /** @@ -303,13 +144,12 @@ public final class Files { * {@link InputStreamReader} that read a file using the given character set. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when reading the file * @return the factory */ public static InputSupplier<InputStreamReader> newReaderSupplier(File file, Charset charset) { - return CharStreams.asInputSupplier(asCharSource(file, charset)); + return CharStreams.newReaderSupplier(newInputStreamSupplier(file), charset); } /** @@ -317,8 +157,7 @@ public final class Files { * that write to a file using the given character set. * * @param file the file to write to - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @return the factory */ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file, @@ -331,15 +170,15 @@ public final class Files { * that write to or append to a file using the given character set. * * @param file the file to write to - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @param append if true, the encoded characters will be appended to the file; * otherwise the file is overwritten * @return the factory */ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file, Charset charset, boolean append) { - return CharStreams.asOutputSupplier(asCharSink(file, charset, modes(append))); + return CharStreams.newWriterSupplier(newOutputStreamSupplier(file, append), + charset); } /** @@ -352,7 +191,23 @@ public final class Files { * @throws IOException if an I/O error occurs */ public static byte[] toByteArray(File file) throws IOException { - return asByteSource(file).read(); + Preconditions.checkArgument(file.length() <= Integer.MAX_VALUE); + if (file.length() == 0) { + // Some special files are length 0 but have content nonetheless. + return ByteStreams.toByteArray(newInputStreamSupplier(file)); + } else { + // Avoid an extra allocation and copy. + byte[] b = new byte[(int) file.length()]; + boolean threw = true; + InputStream in = new FileInputStream(file); + try { + ByteStreams.readFully(in, b); + threw = false; + } finally { + Closeables.close(in, threw); + } + return b; + } } /** @@ -360,13 +215,12 @@ public final class Files { * character set. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when reading the file * @return a string containing all the characters from the file * @throws IOException if an I/O error occurs */ public static String toString(File file, Charset charset) throws IOException { - return asCharSource(file, charset).read(); + return new String(toByteArray(file), charset.name()); } /** @@ -379,7 +233,7 @@ public final class Files { */ public static void copy(InputSupplier<? extends InputStream> from, File to) throws IOException { - ByteStreams.asByteSource(from).copyTo(asByteSink(to)); + ByteStreams.copy(from, newOutputStreamSupplier(to)); } /** @@ -390,7 +244,7 @@ public final class Files { * @throws IOException if an I/O error occurs */ public static void write(byte[] from, File to) throws IOException { - asByteSink(to).write(from); + ByteStreams.write(from, newOutputStreamSupplier(to)); } /** @@ -403,7 +257,7 @@ public final class Files { */ public static void copy(File from, OutputSupplier<? extends OutputStream> to) throws IOException { - asByteSource(from).copyTo(ByteStreams.asByteSink(to)); + ByteStreams.copy(newInputStreamSupplier(from), to); } /** @@ -414,26 +268,21 @@ public final class Files { * @throws IOException if an I/O error occurs */ public static void copy(File from, OutputStream to) throws IOException { - asByteSource(from).copyTo(to); + ByteStreams.copy(newInputStreamSupplier(from), to); } /** * Copies all the bytes from one file to another. - * - * <p><b>Warning:</b> If {@code to} represents an existing file, that file - * will be overwritten with the contents of {@code from}. If {@code to} and - * {@code from} refer to the <i>same</i> file, the contents of that file - * will be deleted. - * + *. * @param from the source file * @param to the destination file * @throws IOException if an I/O error occurs * @throws IllegalArgumentException if {@code from.equals(to)} */ public static void copy(File from, File to) throws IOException { - checkArgument(!from.equals(to), + Preconditions.checkArgument(!from.equals(to), "Source %s and destination %s must be different", from, to); - asByteSource(from).copyTo(asByteSink(to)); + copy(newInputStreamSupplier(from), to); } /** @@ -443,13 +292,12 @@ public final class Files { * * @param from the readable supplier * @param to the destination file - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @throws IOException if an I/O error occurs */ public static <R extends Readable & Closeable> void copy( InputSupplier<R> from, File to, Charset charset) throws IOException { - CharStreams.asCharSource(from).copyTo(asCharSink(to, charset)); + CharStreams.copy(from, newWriterSupplier(to, charset)); } /** @@ -458,13 +306,12 @@ public final class Files { * * @param from the character sequence to write * @param to the destination file - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @throws IOException if an I/O error occurs */ public static void write(CharSequence from, File to, Charset charset) throws IOException { - asCharSink(to, charset).write(from); + write(from, to, charset, false); } /** @@ -473,8 +320,7 @@ public final class Files { * * @param from the character sequence to append * @param to the destination file - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @throws IOException if an I/O error occurs */ public static void append(CharSequence from, File to, Charset charset) @@ -488,14 +334,13 @@ public final class Files { * * @param from the character sequence to append * @param to the destination file - * @param charset the charset used to encode the output stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @param append true to append, false to overwrite * @throws IOException if an I/O error occurs */ private static void write(CharSequence from, File to, Charset charset, boolean append) throws IOException { - asCharSink(to, charset, modes(append)).write(from); + CharStreams.write(from, newWriterSupplier(to, charset, append)); } /** @@ -504,14 +349,13 @@ public final class Files { * character set. * * @param from the source file - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when reading the file * @param to the appendable supplier * @throws IOException if an I/O error occurs */ public static <W extends Appendable & Closeable> void copy(File from, Charset charset, OutputSupplier<W> to) throws IOException { - asCharSource(from, charset).copyTo(CharStreams.asCharSink(to)); + CharStreams.copy(newReaderSupplier(from, charset), to); } /** @@ -519,14 +363,13 @@ public final class Files { * using the given character set. * * @param from the source file - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when reading the file * @param to the appendable object * @throws IOException if an I/O error occurs */ public static void copy(File from, Charset charset, Appendable to) throws IOException { - asCharSource(from, charset).copyTo(to); + CharStreams.copy(newReaderSupplier(from, charset), to); } /** @@ -535,8 +378,6 @@ public final class Files { * @throws IOException if an I/O error occurs */ public static boolean equal(File file1, File file2) throws IOException { - checkNotNull(file1); - checkNotNull(file2); if (file1 == file2 || file1.equals(file2)) { return true; } @@ -551,7 +392,8 @@ public final class Files { if (len1 != 0 && len2 != 0 && len1 != len2) { return false; } - return asByteSource(file1).contentEquals(asByteSource(file2)); + return ByteStreams.equal(newInputStreamSupplier(file1), + newInputStreamSupplier(file2)); } /** @@ -596,7 +438,6 @@ public final class Files { * @throws IOException if an I/O error occurs */ public static void touch(File file) throws IOException { - checkNotNull(file); if (!file.createNewFile() && !file.setLastModified(System.currentTimeMillis())) { throw new IOException("Unable to update modification time of " + file); @@ -614,7 +455,6 @@ public final class Files { * @since 4.0 */ public static void createParentDirs(File file) throws IOException { - checkNotNull(file); File parent = file.getCanonicalFile().getParentFile(); if (parent == null) { /* @@ -642,9 +482,8 @@ public final class Files { * @throws IllegalArgumentException if {@code from.equals(to)} */ public static void move(File from, File to) throws IOException { - checkNotNull(from); - checkNotNull(to); - checkArgument(!from.equals(to), + Preconditions.checkNotNull(to); + Preconditions.checkArgument(!from.equals(to), "Source %s and destination %s must be different", from, to); if (!from.renameTo(to)) { @@ -664,14 +503,13 @@ public final class Files { * trailing whitespace. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @return the first line, or null if the file is empty * @throws IOException if an I/O error occurs */ public static String readFirstLine(File file, Charset charset) throws IOException { - return asCharSource(file, charset).readFirstLine(); + return CharStreams.readFirstLine(Files.newReaderSupplier(file, charset)); } /** @@ -680,8 +518,7 @@ public final class Files { * trailing whitespace. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @return a mutable {@link List} containing all the lines * @throws IOException if an I/O error occurs */ @@ -695,15 +532,15 @@ public final class Files { * false, or we have read all of the lines. * * @param file the file to read from - * @param charset the charset used to decode the input stream; see {@link - * Charsets} for helpful predefined constants + * @param charset the character set used when writing the file * @param callback the {@link LineProcessor} to use to handle the lines * @return the output of processing the lines * @throws IOException if an I/O error occurs */ public static <T> T readLines(File file, Charset charset, LineProcessor<T> callback) throws IOException { - return CharStreams.readLines(newReaderSupplier(file, charset), callback); + return CharStreams.readLines(Files.newReaderSupplier(file, charset), + callback); } /** @@ -731,28 +568,25 @@ public final class Files { * @return the result of {@link Checksum#getValue} after updating the * checksum object with all of the bytes in the file * @throws IOException if an I/O error occurs - * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or - * {@code Hashing.adler32()} hash functions. This method is scheduled - * to be removed in Guava 15.0. */ - @Deprecated public static long getChecksum(File file, Checksum checksum) throws IOException { return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum); } /** - * Computes the hash code of the {@code file} using {@code hashFunction}. + * Computes and returns the digest value for a file. + * The digest object is reset when this method returns successfully. * * @param file the file to read - * @param hashFunction the hash function to use to hash the data - * @return the {@link HashCode} of all of the bytes in the file + * @param md the digest object + * @return the result of {@link MessageDigest#digest()} after updating the + * digest object with all of the bytes in this file * @throws IOException if an I/O error occurs - * @since 12.0 */ - public static HashCode hash(File file, HashFunction hashFunction) + public static byte[] getDigest(File file, MessageDigest md) throws IOException { - return asByteSource(file).hash(hashFunction); + return ByteStreams.getDigest(newInputStreamSupplier(file), md); } /** @@ -772,7 +606,6 @@ public final class Files { * @since 2.0 */ public static MappedByteBuffer map(File file) throws IOException { - checkNotNull(file); return map(file, MapMode.READ_ONLY); } @@ -796,8 +629,6 @@ public final class Files { */ public static MappedByteBuffer map(File file, MapMode mode) throws IOException { - checkNotNull(file); - checkNotNull(mode); if (!file.exists()) { throw new FileNotFoundException(file.toString()); } @@ -827,31 +658,30 @@ public final class Files { */ public static MappedByteBuffer map(File file, MapMode mode, long size) throws FileNotFoundException, IOException { - checkNotNull(file); - checkNotNull(mode); + RandomAccessFile raf = + new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw"); - Closer closer = Closer.create(); + boolean threw = true; try { - RandomAccessFile raf = closer.register( - new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw")); - return map(raf, mode, size); - } catch (Throwable e) { - throw closer.rethrow(e); + MappedByteBuffer mbb = map(raf, mode, size); + threw = false; + return mbb; } finally { - closer.close(); + Closeables.close(raf, threw); } } private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode, long size) throws IOException { - Closer closer = Closer.create(); + FileChannel channel = raf.getChannel(); + + boolean threw = true; try { - FileChannel channel = closer.register(raf.getChannel()); - return channel.map(mode, 0, size); - } catch (Throwable e) { - throw closer.rethrow(e); + MappedByteBuffer mbb = channel.map(mode, 0, size); + threw = false; + return mbb; } finally { - closer.close(); + Closeables.close(channel, threw); } } @@ -877,7 +707,6 @@ public final class Files { * @since 11.0 */ public static String simplifyPath(String pathname) { - checkNotNull(pathname); if (pathname.length() == 0) { return "."; } @@ -927,27 +756,9 @@ public final class Files { * * @since 11.0 */ - public static String getFileExtension(String fullName) { - checkNotNull(fullName); - String fileName = new File(fullName).getName(); + public static String getFileExtension(String fileName) { + checkNotNull(fileName); int dotIndex = fileName.lastIndexOf('.'); return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1); } - - /** - * Returns the file name without its - * <a href="http://en.wikipedia.org/wiki/Filename_extension">file extension</a> or path. This is - * similar to the {@code basename} unix command. The result does not include the '{@code .}'. - * - * @param file The name of the file to trim the extension from. This can be either a fully - * qualified file name (including a path) or just a file name. - * @return The file name without its path or extension. - * @since 14.0 - */ - public static String getNameWithoutExtension(String file) { - checkNotNull(file); - String fileName = new File(file).getName(); - int dotIndex = fileName.lastIndexOf('.'); - return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex); - } } |