• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.io.FileWriteMode.APPEND;
22 
23 import com.google.common.annotations.Beta;
24 import com.google.common.base.Charsets;
25 import com.google.common.base.Joiner;
26 import com.google.common.base.Predicate;
27 import com.google.common.base.Splitter;
28 import com.google.common.collect.ImmutableSet;
29 import com.google.common.collect.Lists;
30 import com.google.common.collect.TreeTraverser;
31 import com.google.common.hash.HashCode;
32 import com.google.common.hash.HashFunction;
33 
34 import java.io.BufferedReader;
35 import java.io.BufferedWriter;
36 import java.io.Closeable;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.InputStreamReader;
44 import java.io.OutputStream;
45 import java.io.OutputStreamWriter;
46 import java.io.RandomAccessFile;
47 import java.nio.MappedByteBuffer;
48 import java.nio.channels.FileChannel;
49 import java.nio.channels.FileChannel.MapMode;
50 import java.nio.charset.Charset;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.List;
55 import java.util.zip.Checksum;
56 
57 /**
58  * Provides utility methods for working with files.
59  *
60  * <p>All method parameters must be non-null unless documented otherwise.
61  *
62  * @author Chris Nokleberg
63  * @author Colin Decker
64  * @since 1.0
65  */
66 @Beta
67 public final class Files {
68 
69   /** Maximum loop count when creating temp directories. */
70   private static final int TEMP_DIR_ATTEMPTS = 10000;
71 
Files()72   private Files() {}
73 
74   /**
75    * Returns a buffered reader that reads from a file using the given
76    * character set.
77    *
78    * @param file the file to read from
79    * @param charset the charset used to decode the input stream; see {@link
80    *     Charsets} for helpful predefined constants
81    * @return the buffered reader
82    */
newReader(File file, Charset charset)83   public static BufferedReader newReader(File file, Charset charset)
84       throws FileNotFoundException {
85     checkNotNull(file);
86     checkNotNull(charset);
87     return new BufferedReader(
88         new InputStreamReader(new FileInputStream(file), charset));
89   }
90 
91   /**
92    * Returns a buffered writer that writes to a file using the given
93    * character set.
94    *
95    * @param file the file to write to
96    * @param charset the charset used to encode the output stream; see {@link
97    *     Charsets} for helpful predefined constants
98    * @return the buffered writer
99    */
newWriter(File file, Charset charset)100   public static BufferedWriter newWriter(File file, Charset charset)
101       throws FileNotFoundException {
102     checkNotNull(file);
103     checkNotNull(charset);
104     return new BufferedWriter(
105         new OutputStreamWriter(new FileOutputStream(file), charset));
106   }
107 
108   /**
109    * Returns a new {@link ByteSource} for reading bytes from the given file.
110    *
111    * @since 14.0
112    */
asByteSource(File file)113   public static ByteSource asByteSource(File file) {
114     return new FileByteSource(file);
115   }
116 
117   private static final class FileByteSource extends ByteSource {
118 
119     private final File file;
120 
FileByteSource(File file)121     private FileByteSource(File file) {
122       this.file = checkNotNull(file);
123     }
124 
125     @Override
openStream()126     public FileInputStream openStream() throws IOException {
127       return new FileInputStream(file);
128     }
129 
130     @Override
size()131     public long size() throws IOException {
132       if (!file.isFile()) {
133         throw new FileNotFoundException(file.toString());
134       }
135       return file.length();
136     }
137 
138     @Override
read()139     public byte[] read() throws IOException {
140       Closer closer = Closer.create();
141       try {
142         FileInputStream in = closer.register(openStream());
143         return readFile(in, in.getChannel().size());
144       } catch (Throwable e) {
145         throw closer.rethrow(e);
146       } finally {
147         closer.close();
148       }
149     }
150 
151     @Override
toString()152     public String toString() {
153       return "Files.asByteSource(" + file + ")";
154     }
155   }
156 
157   /**
158    * Reads a file of the given expected size from the given input stream, if
159    * it will fit into a byte array. This method handles the case where the file
160    * size changes between when the size is read and when the contents are read
161    * from the stream.
162    */
readFile( InputStream in, long expectedSize)163   static byte[] readFile(
164       InputStream in, long expectedSize) throws IOException {
165     if (expectedSize > Integer.MAX_VALUE) {
166       throw new OutOfMemoryError("file is too large to fit in a byte array: "
167           + expectedSize + " bytes");
168     }
169 
170     // some special files may return size 0 but have content, so read
171     // the file normally in that case
172     return expectedSize == 0
173         ? ByteStreams.toByteArray(in)
174         : ByteStreams.toByteArray(in, (int) expectedSize);
175   }
176 
177   /**
178    * Returns a new {@link ByteSink} for writing bytes to the given file. The
179    * given {@code modes} control how the file is opened for writing. When no
180    * mode is provided, the file will be truncated before writing. When the
181    * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will
182    * append to the end of the file without truncating it.
183    *
184    * @since 14.0
185    */
asByteSink(File file, FileWriteMode... modes)186   public static ByteSink asByteSink(File file, FileWriteMode... modes) {
187     return new FileByteSink(file, modes);
188   }
189 
190   private static final class FileByteSink extends ByteSink {
191 
192     private final File file;
193     private final ImmutableSet<FileWriteMode> modes;
194 
FileByteSink(File file, FileWriteMode... modes)195     private FileByteSink(File file, FileWriteMode... modes) {
196       this.file = checkNotNull(file);
197       this.modes = ImmutableSet.copyOf(modes);
198     }
199 
200     @Override
openStream()201     public FileOutputStream openStream() throws IOException {
202       return new FileOutputStream(file, modes.contains(APPEND));
203     }
204 
205     @Override
toString()206     public String toString() {
207       return "Files.asByteSink(" + file + ", " + modes + ")";
208     }
209   }
210 
211   /**
212    * Returns a new {@link CharSource} for reading character data from the given
213    * file using the given character set.
214    *
215    * @since 14.0
216    */
asCharSource(File file, Charset charset)217   public static CharSource asCharSource(File file, Charset charset) {
218     return asByteSource(file).asCharSource(charset);
219   }
220 
221   /**
222    * Returns a new {@link CharSink} for writing character data to the given
223    * file using the given character set. The given {@code modes} control how
224    * the file is opened for writing. When no mode is provided, the file
225    * will be truncated before writing. When the
226    * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will
227    * append to the end of the file without truncating it.
228    *
229    * @since 14.0
230    */
asCharSink(File file, Charset charset, FileWriteMode... modes)231   public static CharSink asCharSink(File file, Charset charset,
232       FileWriteMode... modes) {
233     return asByteSink(file, modes).asCharSink(charset);
234   }
235 
236   /**
237    * Returns a factory that will supply instances of {@link FileInputStream}
238    * that read from a file.
239    *
240    * @param file the file to read from
241    * @return the factory
242    * @deprecated Use {@link #asByteSource(File)}. This method is scheduled for
243    *     removal in Guava 18.0.
244    */
245   @Deprecated
newInputStreamSupplier( final File file)246   public static InputSupplier<FileInputStream> newInputStreamSupplier(
247       final File file) {
248     return ByteStreams.asInputSupplier(asByteSource(file));
249   }
250 
251   /**
252    * Returns a factory that will supply instances of {@link FileOutputStream}
253    * that write to a file.
254    *
255    * @param file the file to write to
256    * @return the factory
257    * @deprecated Use {@link #asByteSink(File)}. This method is scheduled for
258    *     removal in Guava 18.0.
259    */
260   @Deprecated
newOutputStreamSupplier( File file)261   public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
262       File file) {
263     return newOutputStreamSupplier(file, false);
264   }
265 
266   /**
267    * Returns a factory that will supply instances of {@link FileOutputStream}
268    * that write to or append to a file.
269    *
270    * @param file the file to write to
271    * @param append if true, the encoded characters will be appended to the file;
272    *     otherwise the file is overwritten
273    * @return the factory
274    * @deprecated Use {@link #asByteSink(File, FileWriteMode...)}, passing
275    *     {@link FileWriteMode#APPEND} for append. This method is scheduled for
276    *     removal in Guava 18.0.
277    */
278   @Deprecated
newOutputStreamSupplier( final File file, final boolean append)279   public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
280       final File file, final boolean append) {
281     return ByteStreams.asOutputSupplier(asByteSink(file, modes(append)));
282   }
283 
modes(boolean append)284   private static FileWriteMode[] modes(boolean append) {
285     return append
286         ? new FileWriteMode[]{ FileWriteMode.APPEND }
287         : new FileWriteMode[0];
288   }
289 
290   /**
291    * Returns a factory that will supply instances of
292    * {@link InputStreamReader} that read a file using the given character set.
293    *
294    * @param file the file to read from
295    * @param charset the charset used to decode the input stream; see {@link
296    *     Charsets} for helpful predefined constants
297    * @return the factory
298    * @deprecated Use {@link #asCharSource(File, Charset)}. This method is
299    *     scheduled for removal in Guava 18.0.
300    */
301   @Deprecated
newReaderSupplier(File file, Charset charset)302   public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
303       Charset charset) {
304     return CharStreams.asInputSupplier(asCharSource(file, charset));
305   }
306 
307   /**
308    * Returns a factory that will supply instances of {@link OutputStreamWriter}
309    * that write to a file using the given character set.
310    *
311    * @param file the file to write to
312    * @param charset the charset used to encode the output stream; see {@link
313    *     Charsets} for helpful predefined constants
314    * @return the factory
315    * @deprecated Use {@link #asCharSink(File, Charset)}. This method is
316    *     scheduled for removal in Guava 18.0.
317    */
318   @Deprecated
newWriterSupplier(File file, Charset charset)319   public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
320       Charset charset) {
321     return newWriterSupplier(file, charset, false);
322   }
323 
324   /**
325    * Returns a factory that will supply instances of {@link OutputStreamWriter}
326    * that write to or append to a file using the given character set.
327    *
328    * @param file the file to write to
329    * @param charset the charset used to encode the output stream; see {@link
330    *     Charsets} for helpful predefined constants
331    * @param append if true, the encoded characters will be appended to the file;
332    *     otherwise the file is overwritten
333    * @return the factory
334    * @deprecated Use {@link #asCharSink(File, Charset, FileWriteMode...)},
335    *     passing {@link FileWriteMode#APPEND} for append. This method is
336    *     scheduled for removal in Guava 18.0.
337    */
338   @Deprecated
newWriterSupplier(File file, Charset charset, boolean append)339   public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
340       Charset charset, boolean append) {
341     return CharStreams.asOutputSupplier(asCharSink(file, charset, modes(append)));
342   }
343 
344   /**
345    * Reads all bytes from a file into a byte array.
346    *
347    * @param file the file to read from
348    * @return a byte array containing all the bytes from file
349    * @throws IllegalArgumentException if the file is bigger than the largest
350    *     possible byte array (2^31 - 1)
351    * @throws IOException if an I/O error occurs
352    */
toByteArray(File file)353   public static byte[] toByteArray(File file) throws IOException {
354     return asByteSource(file).read();
355   }
356 
357   /**
358    * Reads all characters from a file into a {@link String}, using the given
359    * character set.
360    *
361    * @param file the file to read from
362    * @param charset the charset used to decode the input stream; see {@link
363    *     Charsets} for helpful predefined constants
364    * @return a string containing all the characters from the file
365    * @throws IOException if an I/O error occurs
366    */
toString(File file, Charset charset)367   public static String toString(File file, Charset charset) throws IOException {
368     return asCharSource(file, charset).read();
369   }
370 
371   /**
372    * Copies to a file all bytes from an {@link InputStream} supplied by a
373    * factory.
374    *
375    * @param from the input factory
376    * @param to the destination file
377    * @throws IOException if an I/O error occurs
378    * @deprecated Use {@code from.copyTo(Files.asByteSink(to))} after changing
379    *     {@code from} to a {@code ByteSource} if necessary. This method is
380    *     scheduled to be removed in Guava 18.0.
381    */
382   @Deprecated
copy(InputSupplier<? extends InputStream> from, File to)383   public static void copy(InputSupplier<? extends InputStream> from, File to)
384       throws IOException {
385     ByteStreams.asByteSource(from).copyTo(asByteSink(to));
386   }
387 
388   /**
389    * Overwrites a file with the contents of a byte array.
390    *
391    * @param from the bytes to write
392    * @param to the destination file
393    * @throws IOException if an I/O error occurs
394    */
write(byte[] from, File to)395   public static void write(byte[] from, File to) throws IOException {
396     asByteSink(to).write(from);
397   }
398 
399   /**
400    * Copies all bytes from a file to an {@link OutputStream} supplied by
401    * a factory.
402    *
403    * @param from the source file
404    * @param to the output factory
405    * @throws IOException if an I/O error occurs
406    * @deprecated Use {@code Files.asByteSource(from).copyTo(to)} after changing
407    *     {@code to} to a {@code ByteSink} if necessary. This method is
408    *     scheduled to be removed in Guava 18.0.
409    */
410   @Deprecated
copy(File from, OutputSupplier<? extends OutputStream> to)411   public static void copy(File from, OutputSupplier<? extends OutputStream> to)
412       throws IOException {
413     asByteSource(from).copyTo(ByteStreams.asByteSink(to));
414   }
415 
416   /**
417    * Copies all bytes from a file to an output stream.
418    *
419    * @param from the source file
420    * @param to the output stream
421    * @throws IOException if an I/O error occurs
422    */
copy(File from, OutputStream to)423   public static void copy(File from, OutputStream to) throws IOException {
424     asByteSource(from).copyTo(to);
425   }
426 
427   /**
428    * Copies all the bytes from one file to another.
429    *
430    * <p><b>Warning:</b> If {@code to} represents an existing file, that file
431    * will be overwritten with the contents of {@code from}. If {@code to} and
432    * {@code from} refer to the <i>same</i> file, the contents of that file
433    * will be deleted.
434    *
435    * @param from the source file
436    * @param to the destination file
437    * @throws IOException if an I/O error occurs
438    * @throws IllegalArgumentException if {@code from.equals(to)}
439    */
copy(File from, File to)440   public static void copy(File from, File to) throws IOException {
441     checkArgument(!from.equals(to),
442         "Source %s and destination %s must be different", from, to);
443     asByteSource(from).copyTo(asByteSink(to));
444   }
445 
446   /**
447    * Copies to a file all characters from a {@link Readable} and
448    * {@link Closeable} object supplied by a factory, using the given
449    * character set.
450    *
451    * @param from the readable supplier
452    * @param to the destination file
453    * @param charset the charset used to encode the output stream; see {@link
454    *     Charsets} for helpful predefined constants
455    * @throws IOException if an I/O error occurs
456    * @deprecated Use {@code from.copyTo(Files.asCharSink(to, charset))} after
457    *     changing {@code from} to a {@code CharSource} if necessary. This
458    *     method is scheduled to be removed in Guava 18.0.
459    */
460   @Deprecated
copy( InputSupplier<R> from, File to, Charset charset)461   public static <R extends Readable & Closeable> void copy(
462       InputSupplier<R> from, File to, Charset charset) throws IOException {
463     CharStreams.asCharSource(from).copyTo(asCharSink(to, charset));
464   }
465 
466   /**
467    * Writes a character sequence (such as a string) to a file using the given
468    * character set.
469    *
470    * @param from the character sequence to write
471    * @param to the destination file
472    * @param charset the charset used to encode the output stream; see {@link
473    *     Charsets} for helpful predefined constants
474    * @throws IOException if an I/O error occurs
475    */
write(CharSequence from, File to, Charset charset)476   public static void write(CharSequence from, File to, Charset charset)
477       throws IOException {
478     asCharSink(to, charset).write(from);
479   }
480 
481   /**
482    * Appends a character sequence (such as a string) to a file using the given
483    * character set.
484    *
485    * @param from the character sequence to append
486    * @param to the destination file
487    * @param charset the charset used to encode the output stream; see {@link
488    *     Charsets} for helpful predefined constants
489    * @throws IOException if an I/O error occurs
490    */
append(CharSequence from, File to, Charset charset)491   public static void append(CharSequence from, File to, Charset charset)
492       throws IOException {
493     write(from, to, charset, true);
494   }
495 
496   /**
497    * Private helper method. Writes a character sequence to a file,
498    * optionally appending.
499    *
500    * @param from the character sequence to append
501    * @param to the destination file
502    * @param charset the charset used to encode the output stream; see {@link
503    *     Charsets} for helpful predefined constants
504    * @param append true to append, false to overwrite
505    * @throws IOException if an I/O error occurs
506    */
write(CharSequence from, File to, Charset charset, boolean append)507   private static void write(CharSequence from, File to, Charset charset,
508       boolean append) throws IOException {
509     asCharSink(to, charset, modes(append)).write(from);
510   }
511 
512   /**
513    * Copies all characters from a file to a {@link Appendable} &
514    * {@link Closeable} object supplied by a factory, using the given
515    * character set.
516    *
517    * @param from the source file
518    * @param charset the charset used to decode the input stream; see {@link
519    *     Charsets} for helpful predefined constants
520    * @param to the appendable supplier
521    * @throws IOException if an I/O error occurs
522    * @deprecated Use {@code Files.asCharSource(from, charset).copyTo(to)} after
523    *     changing {@code to} to a {@code CharSink} if necessary. This method is
524    *     scheduled to be removed in Guava 18.0.
525    */
526   @Deprecated
copy(File from, Charset charset, OutputSupplier<W> to)527   public static <W extends Appendable & Closeable> void copy(File from,
528       Charset charset, OutputSupplier<W> to) throws IOException {
529     asCharSource(from, charset).copyTo(CharStreams.asCharSink(to));
530   }
531 
532   /**
533    * Copies all characters from a file to an appendable object,
534    * using the given character set.
535    *
536    * @param from the source file
537    * @param charset the charset used to decode the input stream; see {@link
538    *     Charsets} for helpful predefined constants
539    * @param to the appendable object
540    * @throws IOException if an I/O error occurs
541    */
copy(File from, Charset charset, Appendable to)542   public static void copy(File from, Charset charset, Appendable to)
543       throws IOException {
544     asCharSource(from, charset).copyTo(to);
545   }
546 
547   /**
548    * Returns true if the files contains the same bytes.
549    *
550    * @throws IOException if an I/O error occurs
551    */
equal(File file1, File file2)552   public static boolean equal(File file1, File file2) throws IOException {
553     checkNotNull(file1);
554     checkNotNull(file2);
555     if (file1 == file2 || file1.equals(file2)) {
556       return true;
557     }
558 
559     /*
560      * Some operating systems may return zero as the length for files
561      * denoting system-dependent entities such as devices or pipes, in
562      * which case we must fall back on comparing the bytes directly.
563      */
564     long len1 = file1.length();
565     long len2 = file2.length();
566     if (len1 != 0 && len2 != 0 && len1 != len2) {
567       return false;
568     }
569     return asByteSource(file1).contentEquals(asByteSource(file2));
570   }
571 
572   /**
573    * Atomically creates a new directory somewhere beneath the system's
574    * temporary directory (as defined by the {@code java.io.tmpdir} system
575    * property), and returns its name.
576    *
577    * <p>Use this method instead of {@link File#createTempFile(String, String)}
578    * when you wish to create a directory, not a regular file.  A common pitfall
579    * is to call {@code createTempFile}, delete the file and create a
580    * directory in its place, but this leads a race condition which can be
581    * exploited to create security vulnerabilities, especially when executable
582    * files are to be written into the directory.
583    *
584    * <p>This method assumes that the temporary volume is writable, has free
585    * inodes and free blocks, and that it will not be called thousands of times
586    * per second.
587    *
588    * @return the newly-created directory
589    * @throws IllegalStateException if the directory could not be created
590    */
createTempDir()591   public static File createTempDir() {
592     File baseDir = new File(System.getProperty("java.io.tmpdir"));
593     String baseName = System.currentTimeMillis() + "-";
594 
595     for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
596       File tempDir = new File(baseDir, baseName + counter);
597       if (tempDir.mkdir()) {
598         return tempDir;
599       }
600     }
601     throw new IllegalStateException("Failed to create directory within "
602         + TEMP_DIR_ATTEMPTS + " attempts (tried "
603         + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
604   }
605 
606   /**
607    * Creates an empty file or updates the last updated timestamp on the
608    * same as the unix command of the same name.
609    *
610    * @param file the file to create or update
611    * @throws IOException if an I/O error occurs
612    */
touch(File file)613   public static void touch(File file) throws IOException {
614     checkNotNull(file);
615     if (!file.createNewFile()
616         && !file.setLastModified(System.currentTimeMillis())) {
617       throw new IOException("Unable to update modification time of " + file);
618     }
619   }
620 
621   /**
622    * Creates any necessary but nonexistent parent directories of the specified
623    * file. Note that if this operation fails it may have succeeded in creating
624    * some (but not all) of the necessary parent directories.
625    *
626    * @throws IOException if an I/O error occurs, or if any necessary but
627    *     nonexistent parent directories of the specified file could not be
628    *     created.
629    * @since 4.0
630    */
createParentDirs(File file)631   public static void createParentDirs(File file) throws IOException {
632     checkNotNull(file);
633     File parent = file.getCanonicalFile().getParentFile();
634     if (parent == null) {
635       /*
636        * The given directory is a filesystem root. All zero of its ancestors
637        * exist. This doesn't mean that the root itself exists -- consider x:\ on
638        * a Windows machine without such a drive -- or even that the caller can
639        * create it, but this method makes no such guarantees even for non-root
640        * files.
641        */
642       return;
643     }
644     parent.mkdirs();
645     if (!parent.isDirectory()) {
646       throw new IOException("Unable to create parent directories of " + file);
647     }
648   }
649 
650   /**
651    * Moves a file from one path to another. This method can rename a file
652    * and/or move it to a different directory. In either case {@code to} must
653    * be the target path for the file itself; not just the new name for the
654    * file or the path to the new parent directory.
655    *
656    * @param from the source file
657    * @param to the destination file
658    * @throws IOException if an I/O error occurs
659    * @throws IllegalArgumentException if {@code from.equals(to)}
660    */
move(File from, File to)661   public static void move(File from, File to) throws IOException {
662     checkNotNull(from);
663     checkNotNull(to);
664     checkArgument(!from.equals(to),
665         "Source %s and destination %s must be different", from, to);
666 
667     if (!from.renameTo(to)) {
668       copy(from, to);
669       if (!from.delete()) {
670         if (!to.delete()) {
671           throw new IOException("Unable to delete " + to);
672         }
673         throw new IOException("Unable to delete " + from);
674       }
675     }
676   }
677 
678   /**
679    * Reads the first line from a file. The line does not include
680    * line-termination characters, but does include other leading and
681    * trailing whitespace.
682    *
683    * @param file the file to read from
684    * @param charset the charset used to decode the input stream; see {@link
685    *     Charsets} for helpful predefined constants
686    * @return the first line, or null if the file is empty
687    * @throws IOException if an I/O error occurs
688    */
readFirstLine(File file, Charset charset)689   public static String readFirstLine(File file, Charset charset)
690       throws IOException {
691     return asCharSource(file, charset).readFirstLine();
692   }
693 
694   /**
695    * Reads all of the lines from a file. The lines do not include
696    * line-termination characters, but do include other leading and
697    * trailing whitespace.
698    *
699    * <p>This method returns a mutable {@code List}. For an
700    * {@code ImmutableList}, use
701    * {@code Files.asCharSource(file, charset).readLines()}.
702    *
703    * @param file the file to read from
704    * @param charset the charset used to decode the input stream; see {@link
705    *     Charsets} for helpful predefined constants
706    * @return a mutable {@link List} containing all the lines
707    * @throws IOException if an I/O error occurs
708    */
readLines(File file, Charset charset)709   public static List<String> readLines(File file, Charset charset)
710       throws IOException {
711     // don't use asCharSource(file, charset).readLines() because that returns
712     // an immutable list, which would change the behavior of this method
713     return readLines(file, charset, new LineProcessor<List<String>>() {
714       final List<String> result = Lists.newArrayList();
715 
716       @Override
717       public boolean processLine(String line) {
718         result.add(line);
719         return true;
720       }
721 
722       @Override
723       public List<String> getResult() {
724         return result;
725       }
726     });
727   }
728 
729   /**
730    * Streams lines from a {@link File}, stopping when our callback returns
731    * false, or we have read all of the lines.
732    *
733    * @param file the file to read from
734    * @param charset the charset used to decode the input stream; see {@link
735    *     Charsets} for helpful predefined constants
736    * @param callback the {@link LineProcessor} to use to handle the lines
737    * @return the output of processing the lines
738    * @throws IOException if an I/O error occurs
739    */
readLines(File file, Charset charset, LineProcessor<T> callback)740   public static <T> T readLines(File file, Charset charset,
741       LineProcessor<T> callback) throws IOException {
742     return CharStreams.readLines(newReaderSupplier(file, charset), callback);
743   }
744 
745   /**
746    * Process the bytes of a file.
747    *
748    * <p>(If this seems too complicated, maybe you're looking for
749    * {@link #toByteArray}.)
750    *
751    * @param file the file to read
752    * @param processor the object to which the bytes of the file are passed.
753    * @return the result of the byte processor
754    * @throws IOException if an I/O error occurs
755    */
readBytes(File file, ByteProcessor<T> processor)756   public static <T> T readBytes(File file, ByteProcessor<T> processor)
757       throws IOException {
758     return ByteStreams.readBytes(newInputStreamSupplier(file), processor);
759   }
760 
761   /**
762    * Computes and returns the checksum value for a file.
763    * The checksum object is reset when this method returns successfully.
764    *
765    * @param file the file to read
766    * @param checksum the checksum object
767    * @return the result of {@link Checksum#getValue} after updating the
768    *     checksum object with all of the bytes in the file
769    * @throws IOException if an I/O error occurs
770    * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
771    *     {@code Hashing.adler32()} hash functions. This method is scheduled
772    *     to be removed in Guava 15.0.
773    */
774   @Deprecated
getChecksum(File file, Checksum checksum)775   public static long getChecksum(File file, Checksum checksum)
776       throws IOException {
777     return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum);
778   }
779 
780   /**
781    * Computes the hash code of the {@code file} using {@code hashFunction}.
782    *
783    * @param file the file to read
784    * @param hashFunction the hash function to use to hash the data
785    * @return the {@link HashCode} of all of the bytes in the file
786    * @throws IOException if an I/O error occurs
787    * @since 12.0
788    */
hash(File file, HashFunction hashFunction)789   public static HashCode hash(File file, HashFunction hashFunction)
790       throws IOException {
791     return asByteSource(file).hash(hashFunction);
792   }
793 
794   /**
795    * Fully maps a file read-only in to memory as per
796    * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}.
797    *
798    * <p>Files are mapped from offset 0 to its length.
799    *
800    * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
801    *
802    * @param file the file to map
803    * @return a read-only buffer reflecting {@code file}
804    * @throws FileNotFoundException if the {@code file} does not exist
805    * @throws IOException if an I/O error occurs
806    *
807    * @see FileChannel#map(MapMode, long, long)
808    * @since 2.0
809    */
map(File file)810   public static MappedByteBuffer map(File file) throws IOException {
811     checkNotNull(file);
812     return map(file, MapMode.READ_ONLY);
813   }
814 
815   /**
816    * Fully maps a file in to memory as per
817    * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
818    * using the requested {@link MapMode}.
819    *
820    * <p>Files are mapped from offset 0 to its length.
821    *
822    * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
823    *
824    * @param file the file to map
825    * @param mode the mode to use when mapping {@code file}
826    * @return a buffer reflecting {@code file}
827    * @throws FileNotFoundException if the {@code file} does not exist
828    * @throws IOException if an I/O error occurs
829    *
830    * @see FileChannel#map(MapMode, long, long)
831    * @since 2.0
832    */
map(File file, MapMode mode)833   public static MappedByteBuffer map(File file, MapMode mode)
834       throws IOException {
835     checkNotNull(file);
836     checkNotNull(mode);
837     if (!file.exists()) {
838       throw new FileNotFoundException(file.toString());
839     }
840     return map(file, mode, file.length());
841   }
842 
843   /**
844    * Maps a file in to memory as per
845    * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
846    * using the requested {@link MapMode}.
847    *
848    * <p>Files are mapped from offset 0 to {@code size}.
849    *
850    * <p>If the mode is {@link MapMode#READ_WRITE} and the file does not exist,
851    * it will be created with the requested {@code size}. Thus this method is
852    * useful for creating memory mapped files which do not yet exist.
853    *
854    * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
855    *
856    * @param file the file to map
857    * @param mode the mode to use when mapping {@code file}
858    * @return a buffer reflecting {@code file}
859    * @throws IOException if an I/O error occurs
860    *
861    * @see FileChannel#map(MapMode, long, long)
862    * @since 2.0
863    */
map(File file, MapMode mode, long size)864   public static MappedByteBuffer map(File file, MapMode mode, long size)
865       throws FileNotFoundException, IOException {
866     checkNotNull(file);
867     checkNotNull(mode);
868 
869     Closer closer = Closer.create();
870     try {
871       RandomAccessFile raf = closer.register(
872           new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw"));
873       return map(raf, mode, size);
874     } catch (Throwable e) {
875       throw closer.rethrow(e);
876     } finally {
877       closer.close();
878     }
879   }
880 
map(RandomAccessFile raf, MapMode mode, long size)881   private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode,
882       long size) throws IOException {
883     Closer closer = Closer.create();
884     try {
885       FileChannel channel = closer.register(raf.getChannel());
886       return channel.map(mode, 0, size);
887     } catch (Throwable e) {
888       throw closer.rethrow(e);
889     } finally {
890       closer.close();
891     }
892   }
893 
894   /**
895    * Returns the lexically cleaned form of the path name, <i>usually</i> (but
896    * not always) equivalent to the original. The following heuristics are used:
897    *
898    * <ul>
899    * <li>empty string becomes .
900    * <li>. stays as .
901    * <li>fold out ./
902    * <li>fold out ../ when possible
903    * <li>collapse multiple slashes
904    * <li>delete trailing slashes (unless the path is just "/")
905    * </ul>
906    *
907    * <p>These heuristics do not always match the behavior of the filesystem. In
908    * particular, consider the path {@code a/../b}, which {@code simplifyPath}
909    * will change to {@code b}. If {@code a} is a symlink to {@code x}, {@code
910    * a/../b} may refer to a sibling of {@code x}, rather than the sibling of
911    * {@code a} referred to by {@code b}.
912    *
913    * @since 11.0
914    */
simplifyPath(String pathname)915   public static String simplifyPath(String pathname) {
916     checkNotNull(pathname);
917     if (pathname.length() == 0) {
918       return ".";
919     }
920 
921     // split the path apart
922     Iterable<String> components =
923         Splitter.on('/').omitEmptyStrings().split(pathname);
924     List<String> path = new ArrayList<String>();
925 
926     // resolve ., .., and //
927     for (String component : components) {
928       if (component.equals(".")) {
929         continue;
930       } else if (component.equals("..")) {
931         if (path.size() > 0 && !path.get(path.size() - 1).equals("..")) {
932           path.remove(path.size() - 1);
933         } else {
934           path.add("..");
935         }
936       } else {
937         path.add(component);
938       }
939     }
940 
941     // put it back together
942     String result = Joiner.on('/').join(path);
943     if (pathname.charAt(0) == '/') {
944       result = "/" + result;
945     }
946 
947     while (result.startsWith("/../")) {
948       result = result.substring(3);
949     }
950     if (result.equals("/..")) {
951       result = "/";
952     } else if ("".equals(result)) {
953       result = ".";
954     }
955 
956     return result;
957   }
958 
959   /**
960    * Returns the <a href="http://en.wikipedia.org/wiki/Filename_extension">file
961    * extension</a> for the given file name, or the empty string if the file has
962    * no extension.  The result does not include the '{@code .}'.
963    *
964    * @since 11.0
965    */
getFileExtension(String fullName)966   public static String getFileExtension(String fullName) {
967     checkNotNull(fullName);
968     String fileName = new File(fullName).getName();
969     int dotIndex = fileName.lastIndexOf('.');
970     return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
971   }
972 
973   /**
974    * Returns the file name without its
975    * <a href="http://en.wikipedia.org/wiki/Filename_extension">file extension</a> or path. This is
976    * similar to the {@code basename} unix command. The result does not include the '{@code .}'.
977    *
978    * @param file The name of the file to trim the extension from. This can be either a fully
979    *     qualified file name (including a path) or just a file name.
980    * @return The file name without its path or extension.
981    * @since 14.0
982    */
getNameWithoutExtension(String file)983   public static String getNameWithoutExtension(String file) {
984     checkNotNull(file);
985     String fileName = new File(file).getName();
986     int dotIndex = fileName.lastIndexOf('.');
987     return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
988   }
989 
990   /**
991    * Returns a {@link TreeTraverser} instance for {@link File} trees.
992    *
993    * <p><b>Warning:</b> {@code File} provides no support for symbolic links, and as such there is no
994    * way to ensure that a symbolic link to a directory is not followed when traversing the tree.
995    * In this case, iterables created by this traverser could contain files that are outside of the
996    * given directory or even be infinite if there is a symbolic link loop.
997    *
998    * @since 15.0
999    */
fileTreeTraverser()1000   public static TreeTraverser<File> fileTreeTraverser() {
1001     return FILE_TREE_TRAVERSER;
1002   }
1003 
1004   private static final TreeTraverser<File> FILE_TREE_TRAVERSER = new TreeTraverser<File>() {
1005     @Override
1006     public Iterable<File> children(File file) {
1007       // check isDirectory() just because it may be faster than listFiles() on a non-directory
1008       if (file.isDirectory()) {
1009         File[] files = file.listFiles();
1010         if (files != null) {
1011           return Collections.unmodifiableList(Arrays.asList(files));
1012         }
1013       }
1014 
1015       return Collections.emptyList();
1016     }
1017 
1018     @Override
1019     public String toString() {
1020       return "Files.fileTreeTraverser()";
1021     }
1022   };
1023 
1024   /**
1025    * Returns a predicate that returns the result of {@link File#isDirectory} on input files.
1026    *
1027    * @since 15.0
1028    */
isDirectory()1029   public static Predicate<File> isDirectory() {
1030     return FilePredicate.IS_DIRECTORY;
1031   }
1032 
1033   /**
1034    * Returns a predicate that returns the result of {@link File#isFile} on input files.
1035    *
1036    * @since 15.0
1037    */
isFile()1038   public static Predicate<File> isFile() {
1039     return FilePredicate.IS_FILE;
1040   }
1041 
1042   private enum FilePredicate implements Predicate<File> {
1043     IS_DIRECTORY {
1044       @Override
apply(File file)1045       public boolean apply(File file) {
1046         return file.isDirectory();
1047       }
1048 
1049       @Override
toString()1050       public String toString() {
1051         return "Files.isDirectory()";
1052       }
1053     },
1054 
1055     IS_FILE {
1056       @Override
apply(File file)1057       public boolean apply(File file) {
1058         return file.isFile();
1059       }
1060 
1061       @Override
toString()1062       public String toString() {
1063         return "Files.isFile()";
1064       }
1065     };
1066   }
1067 }
1068