1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.io; 19 20import android.system.ErrnoException; 21import android.system.StructStat; 22import android.system.StructStatVfs; 23import java.net.URI; 24import java.net.URISyntaxException; 25import java.net.URL; 26import java.util.ArrayList; 27import java.util.List; 28import java.util.Random; 29import libcore.io.DeleteOnExit; 30import libcore.io.IoUtils; 31import libcore.io.Libcore; 32import static android.system.OsConstants.*; 33 34/** 35 * An "abstract" representation of a file system entity identified by a 36 * pathname. The pathname may be absolute (relative to the root directory 37 * of the file system) or relative to the current directory in which the program 38 * is running. 39 * 40 * <p>The actual file referenced by a {@code File} may or may not exist. It may 41 * also, despite the name {@code File}, be a directory or other non-regular 42 * file. 43 * 44 * <p>This class provides limited functionality for getting/setting file 45 * permissions, file type, and last modified time. 46 * 47 * <p>On Android strings are converted to UTF-8 byte sequences when sending filenames to 48 * the operating system, and byte sequences returned by the operating system (from the 49 * various {@code list} methods) are converted to strings by decoding them as UTF-8 50 * byte sequences. 51 * 52 * @see java.io.Serializable 53 * @see java.lang.Comparable 54 */ 55public class File implements Serializable, Comparable<File> { 56 57 private static final long serialVersionUID = 301077366599181567L; 58 59 /** 60 * Reusing a Random makes temporary filenames slightly harder to predict. 61 * (Random is thread-safe.) 62 */ 63 private static final Random tempFileRandom = new Random(); 64 65 /** 66 * The system-dependent character used to separate components in filenames ('/'). 67 * Use of this (rather than hard-coding '/') helps portability to other operating systems. 68 * 69 * <p>This field is initialized from the system property "file.separator". 70 * Later changes to that property will have no effect on this field or this class. 71 */ 72 public static final char separatorChar; 73 74 /** 75 * The system-dependent string used to separate components in filenames ('/'). 76 * See {@link #separatorChar}. 77 */ 78 public static final String separator; 79 80 /** 81 * The system-dependent character used to separate components in search paths (':'). 82 * This is used to split such things as the PATH environment variable and classpath 83 * system properties into lists of directories to be searched. 84 * 85 * <p>This field is initialized from the system property "path.separator". 86 * Later changes to that property will have no effect on this field or this class. 87 */ 88 public static final char pathSeparatorChar; 89 90 /** 91 * The system-dependent string used to separate components in search paths (":"). 92 * See {@link #pathSeparatorChar}. 93 */ 94 public static final String pathSeparator; 95 96 /** 97 * The path we return from getPath. This is almost the path we were 98 * given, but without duplicate adjacent slashes and without trailing 99 * slashes (except for the special case of the root directory). This 100 * path may be the empty string. 101 * 102 * This can't be final because we override readObject. 103 */ 104 private String path; 105 106 static { 107 separatorChar = System.getProperty("file.separator", "/").charAt(0); 108 pathSeparatorChar = System.getProperty("path.separator", ":").charAt(0); 109 separator = String.valueOf(separatorChar); 110 pathSeparator = String.valueOf(pathSeparatorChar); 111 } 112 113 /** 114 * Constructs a new file using the specified directory and name. 115 * 116 * @param dir 117 * the directory where the file is stored. 118 * @param name 119 * the file's name. 120 * @throws NullPointerException 121 * if {@code name} is {@code null}. 122 */ 123 public File(File dir, String name) { 124 this(dir == null ? null : dir.getPath(), name); 125 } 126 127 /** 128 * Constructs a new file using the specified path. 129 * 130 * @param path 131 * the path to be used for the file. 132 */ 133 public File(String path) { 134 this.path = fixSlashes(path); 135 } 136 137 /** 138 * Constructs a new File using the specified directory path and file name, 139 * placing a path separator between the two. 140 * 141 * @param dirPath 142 * the path to the directory where the file is stored. 143 * @param name 144 * the file's name. 145 * @throws NullPointerException 146 * if {@code name == null}. 147 */ 148 public File(String dirPath, String name) { 149 if (name == null) { 150 throw new NullPointerException("name == null"); 151 } 152 if (dirPath == null || dirPath.isEmpty()) { 153 this.path = fixSlashes(name); 154 } else if (name.isEmpty()) { 155 this.path = fixSlashes(dirPath); 156 } else { 157 this.path = fixSlashes(join(dirPath, name)); 158 } 159 } 160 161 /** 162 * Constructs a new File using the path of the specified URI. {@code uri} 163 * needs to be an absolute and hierarchical Unified Resource Identifier with 164 * file scheme and non-empty path component, but with undefined authority, 165 * query or fragment components. 166 * 167 * @param uri 168 * the Unified Resource Identifier that is used to construct this 169 * file. 170 * @throws IllegalArgumentException 171 * if {@code uri} does not comply with the conditions above. 172 * @see #toURI 173 * @see java.net.URI 174 */ 175 public File(URI uri) { 176 // check pre-conditions 177 checkURI(uri); 178 this.path = fixSlashes(uri.getPath()); 179 } 180 181 // Removes duplicate adjacent slashes and any trailing slash. 182 private static String fixSlashes(String origPath) { 183 // Remove duplicate adjacent slashes. 184 boolean lastWasSlash = false; 185 char[] newPath = origPath.toCharArray(); 186 int length = newPath.length; 187 int newLength = 0; 188 for (int i = 0; i < length; ++i) { 189 char ch = newPath[i]; 190 if (ch == '/') { 191 if (!lastWasSlash) { 192 newPath[newLength++] = separatorChar; 193 lastWasSlash = true; 194 } 195 } else { 196 newPath[newLength++] = ch; 197 lastWasSlash = false; 198 } 199 } 200 // Remove any trailing slash (unless this is the root of the file system). 201 if (lastWasSlash && newLength > 1) { 202 newLength--; 203 } 204 // Reuse the original string if possible. 205 return (newLength != length) ? new String(newPath, 0, newLength) : origPath; 206 } 207 208 // Joins two path components, adding a separator only if necessary. 209 private static String join(String prefix, String suffix) { 210 int prefixLength = prefix.length(); 211 boolean haveSlash = (prefixLength > 0 && prefix.charAt(prefixLength - 1) == separatorChar); 212 if (!haveSlash) { 213 haveSlash = (suffix.length() > 0 && suffix.charAt(0) == separatorChar); 214 } 215 return haveSlash ? (prefix + suffix) : (prefix + separatorChar + suffix); 216 } 217 218 private static void checkURI(URI uri) { 219 if (!uri.isAbsolute()) { 220 throw new IllegalArgumentException("URI is not absolute: " + uri); 221 } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) { 222 throw new IllegalArgumentException("URI is not hierarchical: " + uri); 223 } 224 if (!"file".equals(uri.getScheme())) { 225 throw new IllegalArgumentException("Expected file scheme in URI: " + uri); 226 } 227 String rawPath = uri.getRawPath(); 228 if (rawPath == null || rawPath.isEmpty()) { 229 throw new IllegalArgumentException("Expected non-empty path in URI: " + uri); 230 } 231 if (uri.getRawAuthority() != null) { 232 throw new IllegalArgumentException("Found authority in URI: " + uri); 233 } 234 if (uri.getRawQuery() != null) { 235 throw new IllegalArgumentException("Found query in URI: " + uri); 236 } 237 if (uri.getRawFragment() != null) { 238 throw new IllegalArgumentException("Found fragment in URI: " + uri); 239 } 240 } 241 242 /** 243 * Returns the file system roots. On Android and other Unix systems, there is 244 * a single root, {@code /}. 245 */ 246 public static File[] listRoots() { 247 return new File[] { new File("/") }; 248 } 249 250 /** 251 * Tests whether or not this process is allowed to execute this file. 252 * Note that this is a best-effort result; the only way to be certain is 253 * to actually attempt the operation. 254 * 255 * @return {@code true} if this file can be executed, {@code false} otherwise. 256 * @since 1.6 257 */ 258 public boolean canExecute() { 259 return doAccess(X_OK); 260 } 261 262 /** 263 * Indicates whether the current context is allowed to read from this file. 264 * 265 * @return {@code true} if this file can be read, {@code false} otherwise. 266 */ 267 public boolean canRead() { 268 return doAccess(R_OK); 269 } 270 271 /** 272 * Indicates whether the current context is allowed to write to this file. 273 * 274 * @return {@code true} if this file can be written, {@code false} 275 * otherwise. 276 */ 277 public boolean canWrite() { 278 return doAccess(W_OK); 279 } 280 281 private boolean doAccess(int mode) { 282 try { 283 return Libcore.os.access(path, mode); 284 } catch (ErrnoException errnoException) { 285 return false; 286 } 287 } 288 289 /** 290 * Returns the relative sort ordering of the paths for this file and the 291 * file {@code another}. The ordering is platform dependent. 292 * 293 * @param another 294 * a file to compare this file to 295 * @return an int determined by comparing the two paths. Possible values are 296 * described in the Comparable interface. 297 * @see Comparable 298 */ 299 public int compareTo(File another) { 300 return this.getPath().compareTo(another.getPath()); 301 } 302 303 /** 304 * Deletes this file. Directories must be empty before they will be deleted. 305 * 306 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 307 * Callers must check the return value. 308 * 309 * @return {@code true} if this file was deleted, {@code false} otherwise. 310 */ 311 public boolean delete() { 312 try { 313 Libcore.os.remove(path); 314 return true; 315 } catch (ErrnoException errnoException) { 316 return false; 317 } 318 } 319 320 /** 321 * Schedules this file to be automatically deleted when the VM terminates normally. 322 * 323 * <p><i>Note that on Android, the application lifecycle does not include VM termination, 324 * so calling this method will not ensure that files are deleted</i>. Instead, you should 325 * use the most appropriate out of: 326 * <ul> 327 * <li>Use a {@code finally} clause to manually invoke {@link #delete}. 328 * <li>Maintain your own set of files to delete, and process it at an appropriate point 329 * in your application's lifecycle. 330 * <li>Use the Unix trick of deleting the file as soon as all readers and writers have 331 * opened it. No new readers/writers will be able to access the file, but all existing 332 * ones will still have access until the last one closes the file. 333 * </ul> 334 */ 335 public void deleteOnExit() { 336 DeleteOnExit.getInstance().addFile(getAbsolutePath()); 337 } 338 339 /** 340 * Compares {@code obj} to this file and returns {@code true} if they 341 * represent the <em>same</em> object using a path specific comparison. 342 * 343 * @param obj 344 * the object to compare this file with. 345 * @return {@code true} if {@code obj} is the same as this object, 346 * {@code false} otherwise. 347 */ 348 @Override 349 public boolean equals(Object obj) { 350 if (!(obj instanceof File)) { 351 return false; 352 } 353 return path.equals(((File) obj).getPath()); 354 } 355 356 /** 357 * Returns a boolean indicating whether this file can be found on the 358 * underlying file system. 359 * 360 * @return {@code true} if this file exists, {@code false} otherwise. 361 */ 362 public boolean exists() { 363 return doAccess(F_OK); 364 } 365 366 /** 367 * Returns the absolute path of this file. An absolute path is a path that starts at a root 368 * of the file system. On Android, there is only one root: {@code /}. 369 * 370 * <p>A common use for absolute paths is when passing paths to a {@code Process} as 371 * command-line arguments, to remove the requirement implied by relative paths, that the 372 * child must have the same working directory as its parent. 373 */ 374 public String getAbsolutePath() { 375 if (isAbsolute()) { 376 return path; 377 } 378 String userDir = System.getProperty("user.dir"); 379 return path.isEmpty() ? userDir : join(userDir, path); 380 } 381 382 /** 383 * Returns a new file constructed using the absolute path of this file. 384 * Equivalent to {@code new File(this.getAbsolutePath())}. 385 */ 386 public File getAbsoluteFile() { 387 return new File(getAbsolutePath()); 388 } 389 390 /** 391 * Returns the canonical path of this file. 392 * An <i>absolute</i> path is one that begins at the root of the file system. 393 * A <i>canonical</i> path is an absolute path with symbolic links 394 * and references to "." or ".." resolved. If a path element does not exist (or 395 * is not searchable), there is a conflict between interpreting canonicalization 396 * as a textual operation (where "a/../b" is "b" even if "a" does not exist) . 397 * 398 * <p>Most callers should use {@link #getAbsolutePath} instead. A canonical path is 399 * significantly more expensive to compute, and not generally useful. The primary 400 * use for canonical paths is determining whether two paths point to the same file by 401 * comparing the canonicalized paths. 402 * 403 * <p>It can be actively harmful to use a canonical path, specifically because 404 * canonicalization removes symbolic links. It's wise to assume that a symbolic link 405 * is present for a reason, and that that reason is because the link may need to change. 406 * Canonicalization removes this layer of indirection. Good code should generally avoid 407 * caching canonical paths. 408 * 409 * @return the canonical path of this file. 410 * @throws IOException 411 * if an I/O error occurs. 412 */ 413 public String getCanonicalPath() throws IOException { 414 return canonicalizePath(getAbsolutePath()); 415 } 416 417 private static native String canonicalizePath(String path); 418 419 /** 420 * Returns a new file created using the canonical path of this file. 421 * Equivalent to {@code new File(this.getCanonicalPath())}. 422 * 423 * @return the new file constructed from this file's canonical path. 424 * @throws IOException 425 * if an I/O error occurs. 426 */ 427 public File getCanonicalFile() throws IOException { 428 return new File(getCanonicalPath()); 429 } 430 431 /** 432 * Returns the name of the file or directory represented by this file. 433 * 434 * @return this file's name or an empty string if there is no name part in 435 * the file's path. 436 */ 437 public String getName() { 438 int separatorIndex = path.lastIndexOf(separator); 439 return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length()); 440 } 441 442 /** 443 * Returns the pathname of the parent of this file. This is the path up to 444 * but not including the last name. {@code null} is returned if there is no 445 * parent. 446 * 447 * @return this file's parent pathname or {@code null}. 448 */ 449 public String getParent() { 450 int length = path.length(), firstInPath = 0; 451 if (separatorChar == '\\' && length > 2 && path.charAt(1) == ':') { 452 firstInPath = 2; 453 } 454 int index = path.lastIndexOf(separatorChar); 455 if (index == -1 && firstInPath > 0) { 456 index = 2; 457 } 458 if (index == -1 || path.charAt(length - 1) == separatorChar) { 459 return null; 460 } 461 if (path.indexOf(separatorChar) == index 462 && path.charAt(firstInPath) == separatorChar) { 463 return path.substring(0, index + 1); 464 } 465 return path.substring(0, index); 466 } 467 468 /** 469 * Returns a new file made from the pathname of the parent of this file. 470 * This is the path up to but not including the last name. {@code null} is 471 * returned when there is no parent. 472 * 473 * @return a new file representing this file's parent or {@code null}. 474 */ 475 public File getParentFile() { 476 String tempParent = getParent(); 477 if (tempParent == null) { 478 return null; 479 } 480 return new File(tempParent); 481 } 482 483 /** 484 * Returns the path of this file. 485 */ 486 public String getPath() { 487 return path; 488 } 489 490 /** 491 * Returns an integer hash code for the receiver. Any two objects for which 492 * {@code equals} returns {@code true} must return the same hash code. 493 * 494 * @return this files's hash value. 495 * @see #equals 496 */ 497 @Override 498 public int hashCode() { 499 return getPath().hashCode() ^ 1234321; 500 } 501 502 /** 503 * Indicates if this file's pathname is absolute. Whether a pathname is 504 * absolute is platform specific. On Android, absolute paths start with 505 * the character '/'. 506 * 507 * @return {@code true} if this file's pathname is absolute, {@code false} 508 * otherwise. 509 * @see #getPath 510 */ 511 public boolean isAbsolute() { 512 return path.length() > 0 && path.charAt(0) == separatorChar; 513 } 514 515 /** 516 * Indicates if this file represents a <em>directory</em> on the 517 * underlying file system. 518 * 519 * @return {@code true} if this file is a directory, {@code false} 520 * otherwise. 521 */ 522 public boolean isDirectory() { 523 try { 524 return S_ISDIR(Libcore.os.stat(path).st_mode); 525 } catch (ErrnoException errnoException) { 526 // The RI returns false on error. (Even for errors like EACCES or ELOOP.) 527 return false; 528 } 529 } 530 531 /** 532 * Indicates if this file represents a <em>file</em> on the underlying 533 * file system. 534 * 535 * @return {@code true} if this file is a file, {@code false} otherwise. 536 */ 537 public boolean isFile() { 538 try { 539 return S_ISREG(Libcore.os.stat(path).st_mode); 540 } catch (ErrnoException errnoException) { 541 // The RI returns false on error. (Even for errors like EACCES or ELOOP.) 542 return false; 543 } 544 } 545 546 /** 547 * Returns whether or not this file is a hidden file as defined by the 548 * operating system. The notion of "hidden" is system-dependent. For Unix 549 * systems a file is considered hidden if its name starts with a ".". For 550 * Windows systems there is an explicit flag in the file system for this 551 * purpose. 552 * 553 * @return {@code true} if the file is hidden, {@code false} otherwise. 554 */ 555 public boolean isHidden() { 556 if (path.isEmpty()) { 557 return false; 558 } 559 return getName().startsWith("."); 560 } 561 562 /** 563 * Returns the time when this file was last modified, measured in 564 * milliseconds since January 1st, 1970, midnight. 565 * Returns 0 if the file does not exist. 566 * 567 * @return the time when this file was last modified. 568 */ 569 public long lastModified() { 570 try { 571 return Libcore.os.stat(path).st_mtime * 1000L; 572 } catch (ErrnoException errnoException) { 573 // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.) 574 return 0; 575 } 576 } 577 578 /** 579 * Sets the time this file was last modified, measured in milliseconds since 580 * January 1st, 1970, midnight. 581 * 582 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 583 * Callers must check the return value. 584 * 585 * @param time 586 * the last modification time for this file. 587 * @return {@code true} if the operation is successful, {@code false} 588 * otherwise. 589 * @throws IllegalArgumentException 590 * if {@code time < 0}. 591 */ 592 public boolean setLastModified(long time) { 593 if (time < 0) { 594 throw new IllegalArgumentException("time < 0"); 595 } 596 return setLastModifiedImpl(path, time); 597 } 598 599 private static native boolean setLastModifiedImpl(String path, long time); 600 601 /** 602 * Equivalent to setWritable(false, false). 603 * 604 * @see #setWritable(boolean, boolean) 605 */ 606 public boolean setReadOnly() { 607 return setWritable(false, false); 608 } 609 610 /** 611 * Manipulates the execute permissions for the abstract path designated by 612 * this file. 613 * 614 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 615 * Callers must check the return value. 616 * 617 * @param executable 618 * To allow execute permission if true, otherwise disallow 619 * @param ownerOnly 620 * To manipulate execute permission only for owner if true, 621 * otherwise for everyone. The manipulation will apply to 622 * everyone regardless of this value if the underlying system 623 * does not distinguish owner and other users. 624 * @return true if and only if the operation succeeded. If the user does not 625 * have permission to change the access permissions of this abstract 626 * pathname the operation will fail. If the underlying file system 627 * does not support execute permission and the value of executable 628 * is false, this operation will fail. 629 * @since 1.6 630 */ 631 public boolean setExecutable(boolean executable, boolean ownerOnly) { 632 return doChmod(ownerOnly ? S_IXUSR : (S_IXUSR | S_IXGRP | S_IXOTH), executable); 633 } 634 635 /** 636 * Equivalent to setExecutable(executable, true). 637 * @see #setExecutable(boolean, boolean) 638 * @since 1.6 639 */ 640 public boolean setExecutable(boolean executable) { 641 return setExecutable(executable, true); 642 } 643 644 /** 645 * Manipulates the read permissions for the abstract path designated by this 646 * file. 647 * 648 * @param readable 649 * To allow read permission if true, otherwise disallow 650 * @param ownerOnly 651 * To manipulate read permission only for owner if true, 652 * otherwise for everyone. The manipulation will apply to 653 * everyone regardless of this value if the underlying system 654 * does not distinguish owner and other users. 655 * @return true if and only if the operation succeeded. If the user does not 656 * have permission to change the access permissions of this abstract 657 * pathname the operation will fail. If the underlying file system 658 * does not support read permission and the value of readable is 659 * false, this operation will fail. 660 * @since 1.6 661 */ 662 public boolean setReadable(boolean readable, boolean ownerOnly) { 663 return doChmod(ownerOnly ? S_IRUSR : (S_IRUSR | S_IRGRP | S_IROTH), readable); 664 } 665 666 /** 667 * Equivalent to setReadable(readable, true). 668 * @see #setReadable(boolean, boolean) 669 * @since 1.6 670 */ 671 public boolean setReadable(boolean readable) { 672 return setReadable(readable, true); 673 } 674 675 /** 676 * Manipulates the write permissions for the abstract path designated by this 677 * file. 678 * 679 * @param writable 680 * To allow write permission if true, otherwise disallow 681 * @param ownerOnly 682 * To manipulate write permission only for owner if true, 683 * otherwise for everyone. The manipulation will apply to 684 * everyone regardless of this value if the underlying system 685 * does not distinguish owner and other users. 686 * @return true if and only if the operation succeeded. If the user does not 687 * have permission to change the access permissions of this abstract 688 * pathname the operation will fail. 689 * @since 1.6 690 */ 691 public boolean setWritable(boolean writable, boolean ownerOnly) { 692 return doChmod(ownerOnly ? S_IWUSR : (S_IWUSR | S_IWGRP | S_IWOTH), writable); 693 } 694 695 /** 696 * Equivalent to setWritable(writable, true). 697 * @see #setWritable(boolean, boolean) 698 * @since 1.6 699 */ 700 public boolean setWritable(boolean writable) { 701 return setWritable(writable, true); 702 } 703 704 private boolean doChmod(int mask, boolean set) { 705 try { 706 StructStat sb = Libcore.os.stat(path); 707 int newMode = set ? (sb.st_mode | mask) : (sb.st_mode & ~mask); 708 Libcore.os.chmod(path, newMode); 709 return true; 710 } catch (ErrnoException errnoException) { 711 return false; 712 } 713 } 714 715 /** 716 * Returns the length of this file in bytes. 717 * Returns 0 if the file does not exist. 718 * The result for a directory is not defined. 719 * 720 * @return the number of bytes in this file. 721 */ 722 public long length() { 723 try { 724 return Libcore.os.stat(path).st_size; 725 } catch (ErrnoException errnoException) { 726 // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.) 727 return 0; 728 } 729 } 730 731 /** 732 * Returns an array of strings with the file names in the directory 733 * represented by this file. The result is {@code null} if this file is not 734 * a directory. 735 * <p> 736 * The entries {@code .} and {@code ..} representing the current and parent 737 * directory are not returned as part of the list. 738 * 739 * @return an array of strings with file names or {@code null}. 740 */ 741 public String[] list() { 742 return listImpl(path); 743 } 744 745 private static native String[] listImpl(String path); 746 747 /** 748 * Gets a list of the files in the directory represented by this file. This 749 * list is then filtered through a FilenameFilter and the names of files 750 * with matching names are returned as an array of strings. Returns 751 * {@code null} if this file is not a directory. If {@code filter} is 752 * {@code null} then all filenames match. 753 * <p> 754 * The entries {@code .} and {@code ..} representing the current and parent 755 * directories are not returned as part of the list. 756 * 757 * @param filter 758 * the filter to match names against, may be {@code null}. 759 * @return an array of files or {@code null}. 760 */ 761 public String[] list(FilenameFilter filter) { 762 String[] filenames = list(); 763 if (filter == null || filenames == null) { 764 return filenames; 765 } 766 List<String> result = new ArrayList<String>(filenames.length); 767 for (String filename : filenames) { 768 if (filter.accept(this, filename)) { 769 result.add(filename); 770 } 771 } 772 return result.toArray(new String[result.size()]); 773 } 774 775 /** 776 * Returns an array of files contained in the directory represented by this 777 * file. The result is {@code null} if this file is not a directory. The 778 * paths of the files in the array are absolute if the path of this file is 779 * absolute, they are relative otherwise. 780 * 781 * @return an array of files or {@code null}. 782 */ 783 public File[] listFiles() { 784 return filenamesToFiles(list()); 785 } 786 787 /** 788 * Gets a list of the files in the directory represented by this file. This 789 * list is then filtered through a FilenameFilter and files with matching 790 * names are returned as an array of files. Returns {@code null} if this 791 * file is not a directory. If {@code filter} is {@code null} then all 792 * filenames match. 793 * <p> 794 * The entries {@code .} and {@code ..} representing the current and parent 795 * directories are not returned as part of the list. 796 * 797 * @param filter 798 * the filter to match names against, may be {@code null}. 799 * @return an array of files or {@code null}. 800 */ 801 public File[] listFiles(FilenameFilter filter) { 802 return filenamesToFiles(list(filter)); 803 } 804 805 /** 806 * Gets a list of the files in the directory represented by this file. This 807 * list is then filtered through a FileFilter and matching files are 808 * returned as an array of files. Returns {@code null} if this file is not a 809 * directory. If {@code filter} is {@code null} then all files match. 810 * <p> 811 * The entries {@code .} and {@code ..} representing the current and parent 812 * directories are not returned as part of the list. 813 * 814 * @param filter 815 * the filter to match names against, may be {@code null}. 816 * @return an array of files or {@code null}. 817 */ 818 public File[] listFiles(FileFilter filter) { 819 File[] files = listFiles(); 820 if (filter == null || files == null) { 821 return files; 822 } 823 List<File> result = new ArrayList<File>(files.length); 824 for (File file : files) { 825 if (filter.accept(file)) { 826 result.add(file); 827 } 828 } 829 return result.toArray(new File[result.size()]); 830 } 831 832 /** 833 * Converts a String[] containing filenames to a File[]. 834 * Note that the filenames must not contain slashes. 835 * This method is to remove duplication in the implementation 836 * of File.list's overloads. 837 */ 838 private File[] filenamesToFiles(String[] filenames) { 839 if (filenames == null) { 840 return null; 841 } 842 int count = filenames.length; 843 File[] result = new File[count]; 844 for (int i = 0; i < count; ++i) { 845 result[i] = new File(this, filenames[i]); 846 } 847 return result; 848 } 849 850 /** 851 * Creates the directory named by this file, assuming its parents exist. 852 * Use {@link #mkdirs} if you also want to create missing parents. 853 * 854 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 855 * Callers must check the return value. Note also that this method returns 856 * false if the directory already existed. If you want to know whether the 857 * directory exists on return, either use {@code (f.mkdir() || f.isDirectory())} 858 * or simply ignore the return value from this method and simply call {@link #isDirectory}. 859 * 860 * @return {@code true} if the directory was created, 861 * {@code false} on failure or if the directory already existed. 862 */ 863 public boolean mkdir() { 864 try { 865 mkdirErrno(); 866 return true; 867 } catch (ErrnoException errnoException) { 868 return false; 869 } 870 } 871 872 private void mkdirErrno() throws ErrnoException { 873 // On Android, we don't want default permissions to allow global access. 874 Libcore.os.mkdir(path, S_IRWXU); 875 } 876 877 /** 878 * Creates the directory named by this file, creating missing parent 879 * directories if necessary. 880 * Use {@link #mkdir} if you don't want to create missing parents. 881 * 882 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 883 * Callers must check the return value. Note also that this method returns 884 * false if the directory already existed. If you want to know whether the 885 * directory exists on return, either use {@code (f.mkdirs() || f.isDirectory())} 886 * or simply ignore the return value from this method and simply call {@link #isDirectory}. 887 * 888 * @return {@code true} if the directory was created, 889 * {@code false} on failure or if the directory already existed. 890 */ 891 public boolean mkdirs() { 892 return mkdirs(false); 893 } 894 895 private boolean mkdirs(boolean resultIfExists) { 896 try { 897 // Try to create the directory directly. 898 mkdirErrno(); 899 return true; 900 } catch (ErrnoException errnoException) { 901 if (errnoException.errno == ENOENT) { 902 // If the parent was missing, try to create it and then try again. 903 File parent = getParentFile(); 904 return parent != null && parent.mkdirs(true) && mkdir(); 905 } else if (errnoException.errno == EEXIST) { 906 return resultIfExists; 907 } 908 return false; 909 } 910 } 911 912 /** 913 * Creates a new, empty file on the file system according to the path 914 * information stored in this file. This method returns true if it creates 915 * a file, false if the file already existed. Note that it returns false 916 * even if the file is not a file (because it's a directory, say). 917 * 918 * <p>This method is not generally useful. For creating temporary files, 919 * use {@link #createTempFile} instead. For reading/writing files, use {@link FileInputStream}, 920 * {@link FileOutputStream}, or {@link RandomAccessFile}, all of which can create files. 921 * 922 * <p>Note that this method does <i>not</i> throw {@code IOException} if the file 923 * already exists, even if it's not a regular file. Callers should always check the 924 * return value, and may additionally want to call {@link #isFile}. 925 * 926 * @return true if the file has been created, false if it 927 * already exists. 928 * @throws IOException if it's not possible to create the file. 929 */ 930 public boolean createNewFile() throws IOException { 931 FileDescriptor fd = null; 932 try { 933 // On Android, we don't want default permissions to allow global access. 934 fd = Libcore.os.open(path, O_RDWR | O_CREAT | O_EXCL, 0600); 935 return true; 936 } catch (ErrnoException errnoException) { 937 if (errnoException.errno == EEXIST) { 938 // The file already exists. 939 return false; 940 } 941 throw errnoException.rethrowAsIOException(); 942 } finally { 943 IoUtils.close(fd); // TODO: should we suppress IOExceptions thrown here? 944 } 945 } 946 947 /** 948 * Creates an empty temporary file using the given prefix and suffix as part 949 * of the file name. If {@code suffix} is null, {@code .tmp} is used. This 950 * method is a convenience method that calls 951 * {@link #createTempFile(String, String, File)} with the third argument 952 * being {@code null}. 953 * 954 * @param prefix 955 * the prefix to the temp file name. 956 * @param suffix 957 * the suffix to the temp file name. 958 * @return the temporary file. 959 * @throws IOException 960 * if an error occurs when writing the file. 961 */ 962 public static File createTempFile(String prefix, String suffix) throws IOException { 963 return createTempFile(prefix, suffix, null); 964 } 965 966 /** 967 * Creates an empty temporary file in the given directory using the given 968 * prefix and suffix as part of the file name. If {@code suffix} is null, {@code .tmp} is used. 969 * 970 * <p>Note that this method does <i>not</i> call {@link #deleteOnExit}, but see the 971 * documentation for that method before you call it manually. 972 * 973 * @param prefix 974 * the prefix to the temp file name. 975 * @param suffix 976 * the suffix to the temp file name. 977 * @param directory 978 * the location to which the temp file is to be written, or 979 * {@code null} for the default location for temporary files, 980 * which is taken from the "java.io.tmpdir" system property. It 981 * may be necessary to set this property to an existing, writable 982 * directory for this method to work properly. 983 * @return the temporary file. 984 * @throws IllegalArgumentException 985 * if the length of {@code prefix} is less than 3. 986 * @throws IOException 987 * if an error occurs when writing the file. 988 */ 989 public static File createTempFile(String prefix, String suffix, File directory) 990 throws IOException { 991 // Force a prefix null check first 992 if (prefix.length() < 3) { 993 throw new IllegalArgumentException("prefix must be at least 3 characters"); 994 } 995 if (suffix == null) { 996 suffix = ".tmp"; 997 } 998 File tmpDirFile = directory; 999 if (tmpDirFile == null) { 1000 String tmpDir = System.getProperty("java.io.tmpdir", "."); 1001 tmpDirFile = new File(tmpDir); 1002 } 1003 File result; 1004 do { 1005 result = new File(tmpDirFile, prefix + tempFileRandom.nextInt() + suffix); 1006 } while (!result.createNewFile()); 1007 return result; 1008 } 1009 1010 /** 1011 * Renames this file to {@code newPath}. This operation is supported for both 1012 * files and directories. 1013 * 1014 * <p>Many failures are possible. Some of the more likely failures include: 1015 * <ul> 1016 * <li>Write permission is required on the directories containing both the source and 1017 * destination paths. 1018 * <li>Search permission is required for all parents of both paths. 1019 * <li>Both paths be on the same mount point. On Android, applications are most likely to hit 1020 * this restriction when attempting to copy between internal storage and an SD card. 1021 * </ul> 1022 * 1023 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure. 1024 * Callers must check the return value. 1025 * 1026 * @param newPath the new path. 1027 * @return true on success. 1028 */ 1029 public boolean renameTo(File newPath) { 1030 try { 1031 Libcore.os.rename(path, newPath.path); 1032 return true; 1033 } catch (ErrnoException errnoException) { 1034 return false; 1035 } 1036 } 1037 1038 /** 1039 * Returns a string containing a concise, human-readable description of this 1040 * file. 1041 * 1042 * @return a printable representation of this file. 1043 */ 1044 @Override 1045 public String toString() { 1046 return path; 1047 } 1048 1049 /** 1050 * Returns a Uniform Resource Identifier for this file. The URI is system 1051 * dependent and may not be transferable between different operating / file 1052 * systems. 1053 * 1054 * @return an URI for this file. 1055 */ 1056 public URI toURI() { 1057 String name = getAbsoluteName(); 1058 try { 1059 if (!name.startsWith("/")) { 1060 // start with sep. 1061 return new URI("file", null, "/" + name, null, null); 1062 } else if (name.startsWith("//")) { 1063 return new URI("file", "", name, null); // UNC path 1064 } 1065 return new URI("file", null, name, null, null); 1066 } catch (URISyntaxException e) { 1067 // this should never happen 1068 return null; 1069 } 1070 } 1071 1072 /** 1073 * Returns a Uniform Resource Locator for this file. The URL is system 1074 * dependent and may not be transferable between different operating / file 1075 * systems. 1076 * 1077 * @return a URL for this file. 1078 * @throws java.net.MalformedURLException 1079 * if the path cannot be transformed into a URL. 1080 * @deprecated Use {@link #toURI} and {@link java.net.URI#toURL} to 1081 * correctly escape illegal characters. 1082 */ 1083 @Deprecated 1084 public URL toURL() throws java.net.MalformedURLException { 1085 String name = getAbsoluteName(); 1086 if (!name.startsWith("/")) { 1087 // start with sep. 1088 return new URL("file", "", -1, "/" + name, null); 1089 } else if (name.startsWith("//")) { 1090 return new URL("file:" + name); // UNC path 1091 } 1092 return new URL("file", "", -1, name, null); 1093 } 1094 1095 // TODO: is this really necessary, or can it be replaced with getAbsolutePath? 1096 private String getAbsoluteName() { 1097 File f = getAbsoluteFile(); 1098 String name = f.getPath(); 1099 if (f.isDirectory() && name.charAt(name.length() - 1) != separatorChar) { 1100 // Directories must end with a slash 1101 name = name + "/"; 1102 } 1103 if (separatorChar != '/') { // Must convert slashes. 1104 name = name.replace(separatorChar, '/'); 1105 } 1106 return name; 1107 } 1108 1109 private void writeObject(ObjectOutputStream stream) throws IOException { 1110 stream.defaultWriteObject(); 1111 stream.writeChar(separatorChar); 1112 } 1113 1114 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 1115 stream.defaultReadObject(); 1116 char inSeparator = stream.readChar(); 1117 this.path = fixSlashes(path.replace(inSeparator, separatorChar)); 1118 } 1119 1120 /** 1121 * Returns the total size in bytes of the partition containing this path. 1122 * Returns 0 if this path does not exist. 1123 * 1124 * @since 1.6 1125 */ 1126 public long getTotalSpace() { 1127 try { 1128 StructStatVfs sb = Libcore.os.statvfs(path); 1129 return sb.f_blocks * sb.f_bsize; // total block count * block size in bytes. 1130 } catch (ErrnoException errnoException) { 1131 return 0; 1132 } 1133 } 1134 1135 /** 1136 * Returns the number of usable free bytes on the partition containing this path. 1137 * Returns 0 if this path does not exist. 1138 * 1139 * <p>Note that this is likely to be an optimistic over-estimate and should not 1140 * be taken as a guarantee your application can actually write this many bytes. 1141 * On Android (and other Unix-based systems), this method returns the number of free bytes 1142 * available to non-root users, regardless of whether you're actually running as root, 1143 * and regardless of any quota or other restrictions that might apply to the user. 1144 * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.) 1145 * 1146 * @since 1.6 1147 */ 1148 public long getUsableSpace() { 1149 try { 1150 StructStatVfs sb = Libcore.os.statvfs(path); 1151 return sb.f_bavail * sb.f_bsize; // non-root free block count * block size in bytes. 1152 } catch (ErrnoException errnoException) { 1153 return 0; 1154 } 1155 } 1156 1157 /** 1158 * Returns the number of free bytes on the partition containing this path. 1159 * Returns 0 if this path does not exist. 1160 * 1161 * <p>Note that this is likely to be an optimistic over-estimate and should not 1162 * be taken as a guarantee your application can actually write this many bytes. 1163 * 1164 * @since 1.6 1165 */ 1166 public long getFreeSpace() { 1167 try { 1168 StructStatVfs sb = Libcore.os.statvfs(path); 1169 return sb.f_bfree * sb.f_bsize; // free block count * block size in bytes. 1170 } catch (ErrnoException errnoException) { 1171 return 0; 1172 } 1173 } 1174} 1175