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