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}