18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)/*
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * Copyright (C) 2007 The Guava Authors
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) *
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License");
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * you may not use this file except in compliance with the License.
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * You may obtain a copy of the License at
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) *
88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) *
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS,
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * See the License for the specific language governing permissions and
148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * limitations under the License.
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) */
168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)package com.google.common.io;
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import static com.google.common.base.Preconditions.checkNotNull;
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import com.google.common.annotations.Beta;
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import com.google.common.base.Joiner;
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import com.google.common.base.Preconditions;
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import com.google.common.base.Splitter;
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.BufferedReader;
278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.BufferedWriter;
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.Closeable;
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.File;
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.FileInputStream;
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.FileNotFoundException;
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.FileOutputStream;
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.IOException;
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.InputStream;
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.InputStreamReader;
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.OutputStream;
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.OutputStreamWriter;
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.io.RandomAccessFile;
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.nio.MappedByteBuffer;
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.nio.channels.FileChannel;
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.nio.channels.FileChannel.MapMode;
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.nio.charset.Charset;
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.security.MessageDigest;
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.util.ArrayList;
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.util.List;
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)import java.util.zip.Checksum;
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)/**
498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * Provides utility methods for working with files.
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) *
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * <p>All method parameters must be non-null unless documented otherwise.
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) *
538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * @author Chris Nokleberg
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * @since 1.0
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) */
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)@Beta
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)public final class Files {
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /** Maximum loop count when creating temp directories. */
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  private static final int TEMP_DIR_ATTEMPTS = 10000;
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  private Files() {}
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /**
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)   * Returns a buffered reader that reads from a file using the given
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)   * character set.
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param file the file to read from
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param charset the character set used when writing the file
708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @return the buffered reader
718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   */
728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  public static BufferedReader newReader(File file, Charset charset)
738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      throws FileNotFoundException {
748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return new BufferedReader(
758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        new InputStreamReader(new FileInputStream(file), charset));
768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /**
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * Returns a buffered writer that writes to a file using the given
808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * character set.
818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *
828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param file the file to write to
838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param charset the character set used when writing the file
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @return the buffered writer
858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   */
868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  public static BufferedWriter newWriter(File file, Charset charset)
878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      throws FileNotFoundException {
888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return new BufferedWriter(
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        new OutputStreamWriter(new FileOutputStream(file), charset));
908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /**
938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * Returns a factory that will supply instances of {@link FileInputStream}
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * that read from a file.
958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *
968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param file the file to read from
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @return the factory
988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   */
998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  public static InputSupplier<FileInputStream> newInputStreamSupplier(
1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      final File file) {
1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Preconditions.checkNotNull(file);
1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return new InputSupplier<FileInputStream>() {
1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      @Override
1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      public FileInputStream getInput() throws IOException {
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return new FileInputStream(file);
1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      }
1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    };
1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /**
1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * Returns a factory that will supply instances of {@link FileOutputStream}
1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * that write to a file.
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *
1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param file the file to write to
1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @return the factory
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   */
1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      File file) {
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return newOutputStreamSupplier(file, false);
1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  /**
1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * Returns a factory that will supply instances of {@link FileOutputStream}
1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * that write to or append to a file.
1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *
1268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param file the file to write to
1278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @param append if true, the encoded characters will be appended to the file;
1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   *     otherwise the file is overwritten
1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   * @return the factory
1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)   */
1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      final File file, final boolean append) {
133    Preconditions.checkNotNull(file);
134    return new OutputSupplier<FileOutputStream>() {
135      @Override
136      public FileOutputStream getOutput() throws IOException {
137        return new FileOutputStream(file, append);
138      }
139    };
140  }
141
142  /**
143   * Returns a factory that will supply instances of
144   * {@link InputStreamReader} that read a file using the given character set.
145   *
146   * @param file the file to read from
147   * @param charset the character set used when reading the file
148   * @return the factory
149   */
150  public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
151      Charset charset) {
152    return CharStreams.newReaderSupplier(newInputStreamSupplier(file), charset);
153  }
154
155  /**
156   * Returns a factory that will supply instances of {@link OutputStreamWriter}
157   * that write to a file using the given character set.
158   *
159   * @param file the file to write to
160   * @param charset the character set used when writing the file
161   * @return the factory
162   */
163  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
164      Charset charset) {
165    return newWriterSupplier(file, charset, false);
166  }
167
168  /**
169   * Returns a factory that will supply instances of {@link OutputStreamWriter}
170   * that write to or append to a file using the given character set.
171   *
172   * @param file the file to write to
173   * @param charset the character set used when writing the file
174   * @param append if true, the encoded characters will be appended to the file;
175   *     otherwise the file is overwritten
176   * @return the factory
177   */
178  public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
179      Charset charset, boolean append) {
180    return CharStreams.newWriterSupplier(newOutputStreamSupplier(file, append),
181        charset);
182  }
183
184  /**
185   * Reads all bytes from a file into a byte array.
186   *
187   * @param file the file to read from
188   * @return a byte array containing all the bytes from file
189   * @throws IllegalArgumentException if the file is bigger than the largest
190   *     possible byte array (2^31 - 1)
191   * @throws IOException if an I/O error occurs
192   */
193  public static byte[] toByteArray(File file) throws IOException {
194    Preconditions.checkArgument(file.length() <= Integer.MAX_VALUE);
195    if (file.length() == 0) {
196      // Some special files are length 0 but have content nonetheless.
197      return ByteStreams.toByteArray(newInputStreamSupplier(file));
198    } else {
199      // Avoid an extra allocation and copy.
200      byte[] b = new byte[(int) file.length()];
201      boolean threw = true;
202      InputStream in = new FileInputStream(file);
203      try {
204        ByteStreams.readFully(in, b);
205        threw = false;
206      } finally {
207        Closeables.close(in, threw);
208      }
209      return b;
210    }
211  }
212
213  /**
214   * Reads all characters from a file into a {@link String}, using the given
215   * character set.
216   *
217   * @param file the file to read from
218   * @param charset the character set used when reading the file
219   * @return a string containing all the characters from the file
220   * @throws IOException if an I/O error occurs
221   */
222  public static String toString(File file, Charset charset) throws IOException {
223    return new String(toByteArray(file), charset.name());
224  }
225
226  /**
227   * Copies to a file all bytes from an {@link InputStream} supplied by a
228   * factory.
229   *
230   * @param from the input factory
231   * @param to the destination file
232   * @throws IOException if an I/O error occurs
233   */
234  public static void copy(InputSupplier<? extends InputStream> from, File to)
235      throws IOException {
236    ByteStreams.copy(from, newOutputStreamSupplier(to));
237  }
238
239  /**
240   * Overwrites a file with the contents of a byte array.
241   *
242   * @param from the bytes to write
243   * @param to the destination file
244   * @throws IOException if an I/O error occurs
245   */
246  public static void write(byte[] from, File to) throws IOException {
247    ByteStreams.write(from, newOutputStreamSupplier(to));
248  }
249
250  /**
251   * Copies all bytes from a file to an {@link OutputStream} supplied by
252   * a factory.
253   *
254   * @param from the source file
255   * @param to the output factory
256   * @throws IOException if an I/O error occurs
257   */
258  public static void copy(File from, OutputSupplier<? extends OutputStream> to)
259      throws IOException {
260    ByteStreams.copy(newInputStreamSupplier(from), to);
261  }
262
263  /**
264   * Copies all bytes from a file to an output stream.
265   *
266   * @param from the source file
267   * @param to the output stream
268   * @throws IOException if an I/O error occurs
269   */
270  public static void copy(File from, OutputStream to) throws IOException {
271    ByteStreams.copy(newInputStreamSupplier(from), to);
272  }
273
274  /**
275   * Copies all the bytes from one file to another.
276   *.
277   * @param from the source file
278   * @param to the destination file
279   * @throws IOException if an I/O error occurs
280   * @throws IllegalArgumentException if {@code from.equals(to)}
281   */
282  public static void copy(File from, File to) throws IOException {
283    Preconditions.checkArgument(!from.equals(to),
284        "Source %s and destination %s must be different", from, to);
285    copy(newInputStreamSupplier(from), to);
286  }
287
288  /**
289   * Copies to a file all characters from a {@link Readable} and
290   * {@link Closeable} object supplied by a factory, using the given
291   * character set.
292   *
293   * @param from the readable supplier
294   * @param to the destination file
295   * @param charset the character set used when writing the file
296   * @throws IOException if an I/O error occurs
297   */
298  public static <R extends Readable & Closeable> void copy(
299      InputSupplier<R> from, File to, Charset charset) throws IOException {
300    CharStreams.copy(from, newWriterSupplier(to, charset));
301  }
302
303  /**
304   * Writes a character sequence (such as a string) to a file using the given
305   * character set.
306   *
307   * @param from the character sequence to write
308   * @param to the destination file
309   * @param charset the character set used when writing the file
310   * @throws IOException if an I/O error occurs
311   */
312  public static void write(CharSequence from, File to, Charset charset)
313      throws IOException {
314    write(from, to, charset, false);
315  }
316
317  /**
318   * Appends a character sequence (such as a string) to a file using the given
319   * character set.
320   *
321   * @param from the character sequence to append
322   * @param to the destination file
323   * @param charset the character set used when writing the file
324   * @throws IOException if an I/O error occurs
325   */
326  public static void append(CharSequence from, File to, Charset charset)
327      throws IOException {
328    write(from, to, charset, true);
329  }
330
331  /**
332   * Private helper method. Writes a character sequence to a file,
333   * optionally appending.
334   *
335   * @param from the character sequence to append
336   * @param to the destination file
337   * @param charset the character set used when writing the file
338   * @param append true to append, false to overwrite
339   * @throws IOException if an I/O error occurs
340   */
341  private static void write(CharSequence from, File to, Charset charset,
342      boolean append) throws IOException {
343    CharStreams.write(from, newWriterSupplier(to, charset, append));
344  }
345
346  /**
347   * Copies all characters from a file to a {@link Appendable} &
348   * {@link Closeable} object supplied by a factory, using the given
349   * character set.
350   *
351   * @param from the source file
352   * @param charset the character set used when reading the file
353   * @param to the appendable supplier
354   * @throws IOException if an I/O error occurs
355   */
356  public static <W extends Appendable & Closeable> void copy(File from,
357      Charset charset, OutputSupplier<W> to) throws IOException {
358    CharStreams.copy(newReaderSupplier(from, charset), to);
359  }
360
361  /**
362   * Copies all characters from a file to an appendable object,
363   * using the given character set.
364   *
365   * @param from the source file
366   * @param charset the character set used when reading the file
367   * @param to the appendable object
368   * @throws IOException if an I/O error occurs
369   */
370  public static void copy(File from, Charset charset, Appendable to)
371      throws IOException {
372    CharStreams.copy(newReaderSupplier(from, charset), to);
373  }
374
375  /**
376   * Returns true if the files contains the same bytes.
377   *
378   * @throws IOException if an I/O error occurs
379   */
380  public static boolean equal(File file1, File file2) throws IOException {
381    if (file1 == file2 || file1.equals(file2)) {
382      return true;
383    }
384
385    /*
386     * Some operating systems may return zero as the length for files
387     * denoting system-dependent entities such as devices or pipes, in
388     * which case we must fall back on comparing the bytes directly.
389     */
390    long len1 = file1.length();
391    long len2 = file2.length();
392    if (len1 != 0 && len2 != 0 && len1 != len2) {
393      return false;
394    }
395    return ByteStreams.equal(newInputStreamSupplier(file1),
396        newInputStreamSupplier(file2));
397  }
398
399  /**
400   * Atomically creates a new directory somewhere beneath the system's
401   * temporary directory (as defined by the {@code java.io.tmpdir} system
402   * property), and returns its name.
403   *
404   * <p>Use this method instead of {@link File#createTempFile(String, String)}
405   * when you wish to create a directory, not a regular file.  A common pitfall
406   * is to call {@code createTempFile}, delete the file and create a
407   * directory in its place, but this leads a race condition which can be
408   * exploited to create security vulnerabilities, especially when executable
409   * files are to be written into the directory.
410   *
411   * <p>This method assumes that the temporary volume is writable, has free
412   * inodes and free blocks, and that it will not be called thousands of times
413   * per second.
414   *
415   * @return the newly-created directory
416   * @throws IllegalStateException if the directory could not be created
417   */
418  public static File createTempDir() {
419    File baseDir = new File(System.getProperty("java.io.tmpdir"));
420    String baseName = System.currentTimeMillis() + "-";
421
422    for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
423      File tempDir = new File(baseDir, baseName + counter);
424      if (tempDir.mkdir()) {
425        return tempDir;
426      }
427    }
428    throw new IllegalStateException("Failed to create directory within "
429        + TEMP_DIR_ATTEMPTS + " attempts (tried "
430        + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
431  }
432
433  /**
434   * Creates an empty file or updates the last updated timestamp on the
435   * same as the unix command of the same name.
436   *
437   * @param file the file to create or update
438   * @throws IOException if an I/O error occurs
439   */
440  public static void touch(File file) throws IOException {
441    if (!file.createNewFile()
442        && !file.setLastModified(System.currentTimeMillis())) {
443      throw new IOException("Unable to update modification time of " + file);
444    }
445  }
446
447  /**
448   * Creates any necessary but nonexistent parent directories of the specified
449   * file. Note that if this operation fails it may have succeeded in creating
450   * some (but not all) of the necessary parent directories.
451   *
452   * @throws IOException if an I/O error occurs, or if any necessary but
453   *     nonexistent parent directories of the specified file could not be
454   *     created.
455   * @since 4.0
456   */
457  public static void createParentDirs(File file) throws IOException {
458    File parent = file.getCanonicalFile().getParentFile();
459    if (parent == null) {
460      /*
461       * The given directory is a filesystem root. All zero of its ancestors
462       * exist. This doesn't mean that the root itself exists -- consider x:\ on
463       * a Windows machine without such a drive -- or even that the caller can
464       * create it, but this method makes no such guarantees even for non-root
465       * files.
466       */
467      return;
468    }
469    parent.mkdirs();
470    if (!parent.isDirectory()) {
471      throw new IOException("Unable to create parent directories of " + file);
472    }
473  }
474
475  /**
476   * Moves the file from one path to another. This method can rename a file or
477   * move it to a different directory, like the Unix {@code mv} command.
478   *
479   * @param from the source file
480   * @param to the destination file
481   * @throws IOException if an I/O error occurs
482   * @throws IllegalArgumentException if {@code from.equals(to)}
483   */
484  public static void move(File from, File to) throws IOException {
485    Preconditions.checkNotNull(to);
486    Preconditions.checkArgument(!from.equals(to),
487        "Source %s and destination %s must be different", from, to);
488
489    if (!from.renameTo(to)) {
490      copy(from, to);
491      if (!from.delete()) {
492        if (!to.delete()) {
493          throw new IOException("Unable to delete " + to);
494        }
495        throw new IOException("Unable to delete " + from);
496      }
497    }
498  }
499
500  /**
501   * Reads the first line from a file. The line does not include
502   * line-termination characters, but does include other leading and
503   * trailing whitespace.
504   *
505   * @param file the file to read from
506   * @param charset the character set used when writing the file
507   * @return the first line, or null if the file is empty
508   * @throws IOException if an I/O error occurs
509   */
510  public static String readFirstLine(File file, Charset charset)
511      throws IOException {
512    return CharStreams.readFirstLine(Files.newReaderSupplier(file, charset));
513  }
514
515  /**
516   * Reads all of the lines from a file. The lines do not include
517   * line-termination characters, but do include other leading and
518   * trailing whitespace.
519   *
520   * @param file the file to read from
521   * @param charset the character set used when writing the file
522   * @return a mutable {@link List} containing all the lines
523   * @throws IOException if an I/O error occurs
524   */
525  public static List<String> readLines(File file, Charset charset)
526      throws IOException {
527    return CharStreams.readLines(Files.newReaderSupplier(file, charset));
528  }
529
530  /**
531   * Streams lines from a {@link File}, stopping when our callback returns
532   * false, or we have read all of the lines.
533   *
534   * @param file the file to read from
535   * @param charset the character set used when writing the file
536   * @param callback the {@link LineProcessor} to use to handle the lines
537   * @return the output of processing the lines
538   * @throws IOException if an I/O error occurs
539   */
540  public static <T> T readLines(File file, Charset charset,
541      LineProcessor<T> callback) throws IOException {
542    return CharStreams.readLines(Files.newReaderSupplier(file, charset),
543        callback);
544  }
545
546  /**
547   * Process the bytes of a file.
548   *
549   * <p>(If this seems too complicated, maybe you're looking for
550   * {@link #toByteArray}.)
551   *
552   * @param file the file to read
553   * @param processor the object to which the bytes of the file are passed.
554   * @return the result of the byte processor
555   * @throws IOException if an I/O error occurs
556   */
557  public static <T> T readBytes(File file, ByteProcessor<T> processor)
558      throws IOException {
559    return ByteStreams.readBytes(newInputStreamSupplier(file), processor);
560  }
561
562  /**
563   * Computes and returns the checksum value for a file.
564   * The checksum object is reset when this method returns successfully.
565   *
566   * @param file the file to read
567   * @param checksum the checksum object
568   * @return the result of {@link Checksum#getValue} after updating the
569   *     checksum object with all of the bytes in the file
570   * @throws IOException if an I/O error occurs
571   */
572  public static long getChecksum(File file, Checksum checksum)
573      throws IOException {
574    return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum);
575  }
576
577  /**
578   * Computes and returns the digest value for a file.
579   * The digest object is reset when this method returns successfully.
580   *
581   * @param file the file to read
582   * @param md the digest object
583   * @return the result of {@link MessageDigest#digest()} after updating the
584   *     digest object with all of the bytes in this file
585   * @throws IOException if an I/O error occurs
586   */
587  public static byte[] getDigest(File file, MessageDigest md)
588      throws IOException {
589    return ByteStreams.getDigest(newInputStreamSupplier(file), md);
590  }
591
592  /**
593   * Fully maps a file read-only in to memory as per
594   * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}.
595   *
596   * <p>Files are mapped from offset 0 to its length.
597   *
598   * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
599   *
600   * @param file the file to map
601   * @return a read-only buffer reflecting {@code file}
602   * @throws FileNotFoundException if the {@code file} does not exist
603   * @throws IOException if an I/O error occurs
604   *
605   * @see FileChannel#map(MapMode, long, long)
606   * @since 2.0
607   */
608  public static MappedByteBuffer map(File file) throws IOException {
609    return map(file, MapMode.READ_ONLY);
610  }
611
612  /**
613   * Fully maps a file in to memory as per
614   * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
615   * using the requested {@link MapMode}.
616   *
617   * <p>Files are mapped from offset 0 to its length.
618   *
619   * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
620   *
621   * @param file the file to map
622   * @param mode the mode to use when mapping {@code file}
623   * @return a buffer reflecting {@code file}
624   * @throws FileNotFoundException if the {@code file} does not exist
625   * @throws IOException if an I/O error occurs
626   *
627   * @see FileChannel#map(MapMode, long, long)
628   * @since 2.0
629   */
630  public static MappedByteBuffer map(File file, MapMode mode)
631      throws IOException {
632    if (!file.exists()) {
633      throw new FileNotFoundException(file.toString());
634    }
635    return map(file, mode, file.length());
636  }
637
638  /**
639   * Maps a file in to memory as per
640   * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
641   * using the requested {@link MapMode}.
642   *
643   * <p>Files are mapped from offset 0 to {@code size}.
644   *
645   * <p>If the mode is {@link MapMode#READ_WRITE} and the file does not exist,
646   * it will be created with the requested {@code size}. Thus this method is
647   * useful for creating memory mapped files which do not yet exist.
648   *
649   * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
650   *
651   * @param file the file to map
652   * @param mode the mode to use when mapping {@code file}
653   * @return a buffer reflecting {@code file}
654   * @throws IOException if an I/O error occurs
655   *
656   * @see FileChannel#map(MapMode, long, long)
657   * @since 2.0
658   */
659  public static MappedByteBuffer map(File file, MapMode mode, long size)
660      throws FileNotFoundException, IOException {
661    RandomAccessFile raf =
662        new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw");
663
664    boolean threw = true;
665    try {
666      MappedByteBuffer mbb = map(raf, mode, size);
667      threw = false;
668      return mbb;
669    } finally {
670      Closeables.close(raf, threw);
671    }
672  }
673
674  private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode,
675      long size) throws IOException {
676    FileChannel channel = raf.getChannel();
677
678    boolean threw = true;
679    try {
680      MappedByteBuffer mbb = channel.map(mode, 0, size);
681      threw = false;
682      return mbb;
683    } finally {
684      Closeables.close(channel, threw);
685    }
686  }
687
688  /**
689   * Returns the lexically cleaned form of the path name, <i>usually</i> (but
690   * not always) equivalent to the original. The following heuristics are used:
691   *
692   * <ul>
693   * <li>empty string becomes .
694   * <li>. stays as .
695   * <li>fold out ./
696   * <li>fold out ../ when possible
697   * <li>collapse multiple slashes
698   * <li>delete trailing slashes (unless the path is just "/")
699   * </ul>
700   *
701   * These heuristics do not always match the behavior of the filesystem. In
702   * particular, consider the path {@code a/../b}, which {@code simplifyPath}
703   * will change to {@code b}. If {@code a} is a symlink to {@code x}, {@code
704   * a/../b} may refer to a sibling of {@code x}, rather than the sibling of
705   * {@code a} referred to by {@code b}.
706   *
707   * @since 11.0
708   */
709  public static String simplifyPath(String pathname) {
710    if (pathname.length() == 0) {
711      return ".";
712    }
713
714    // split the path apart
715    Iterable<String> components =
716        Splitter.on('/').omitEmptyStrings().split(pathname);
717    List<String> path = new ArrayList<String>();
718
719    // resolve ., .., and //
720    for (String component : components) {
721      if (component.equals(".")) {
722        continue;
723      } else if (component.equals("..")) {
724        if (path.size() > 0 && !path.get(path.size() - 1).equals("..")) {
725          path.remove(path.size() - 1);
726        } else {
727          path.add("..");
728        }
729      } else {
730        path.add(component);
731      }
732    }
733
734    // put it back together
735    String result = Joiner.on('/').join(path);
736    if (pathname.charAt(0) == '/') {
737      result = "/" + result;
738    }
739
740    while (result.startsWith("/../")) {
741      result = result.substring(3);
742    }
743    if (result.equals("/..")) {
744      result = "/";
745    } else if ("".equals(result)) {
746      result = ".";
747    }
748
749    return result;
750  }
751
752  /**
753   * Returns the <a href="http://en.wikipedia.org/wiki/Filename_extension">file
754   * extension</a> for the given file name, or the empty string if the file has
755   * no extension.  The result does not include the '{@code .}'.
756   *
757   * @since 11.0
758   */
759  public static String getFileExtension(String fileName) {
760    checkNotNull(fileName);
761    int dotIndex = fileName.lastIndexOf('.');
762    return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
763  }
764}
765