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