blob: ffc20aa171d1204c52ff17c4a88bfb180a7281c3 [file] [log] [blame]
The Android Open Source Project0eec4642012-04-01 00:00:00 -07001/*
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// BEGIN android-note
19// We've dropped Windows support, except where it's exposed: we still support
20// non-Unix separators in serialized File objects, for example, but we don't
21// have any code for UNC paths or case-insensitivity.
22// We've also changed the JNI interface to better match what the Java actually wants.
23// (The JNI implementation is also much simpler.)
24// Some methods have been rewritten to reduce unnecessary allocation.
25// Some duplication has been factored out.
26// END android-note
27
28package java.io;
29
30import java.net.URI;
31import java.net.URISyntaxException;
32import java.net.URL;
33import java.security.AccessController;
34import java.util.ArrayList;
35import java.util.List;
36import java.util.Random;
37import org.apache.harmony.luni.util.DeleteOnExit;
38import org.apache.harmony.luni.util.PriviAction;
39
40/**
41 * An "abstract" representation of a file system entity identified by a
42 * pathname. The pathname may be absolute (relative to the root directory
43 * of the file system) or relative to the current directory in which the program
44 * is running.
45 * <p>
46 * The actual file referenced by a {@code File} may or may not exist. It may
47 * also, despite the name {@code File}, be a directory or other non-regular
48 * file.
49 * <p>
50 * This class provides limited functionality for getting/setting file
51 * permissions, file type, and last modified time.
52 * <p>
53 * Although Java doesn't specify a character encoding for filenames, on Android
54 * Java strings are converted to UTF-8 byte sequences when sending filenames to
55 * the operating system, and byte sequences returned by the operating system
56 * (from the various {@code list} methods) are converted to Java strings by
57 * decoding them as UTF-8 byte sequences.
58 *
59 * @see java.io.Serializable
60 * @see java.lang.Comparable
61 */
62public class File implements Serializable, Comparable<File> {
63
64 private static final long serialVersionUID = 301077366599181567L;
65
66 /**
67 * The system-dependent character used to separate components in filenames ('/').
68 * Use of this (rather than hard-coding '/') helps portability to other operating systems.
69 *
70 * <p>This field is initialized from the system property "file.separator".
71 * Later changes to that property will have no effect on this field or this class.
72 */
73 public static final char separatorChar;
74
75 /**
76 * The system-dependent string used to separate components in filenames ('/').
77 * See {@link #separatorChar}.
78 */
79 public static final String separator;
80
81 /**
82 * The system-dependent character used to separate components in search paths (':').
83 * This is used to split such things as the PATH environment variable and classpath
84 * system properties into lists of directories to be searched.
85 *
86 * <p>This field is initialized from the system property "path.separator".
87 * Later changes to that property will have no effect on this field or this class.
88 */
89 public static final char pathSeparatorChar;
90
91 /**
92 * The system-dependent string used to separate components in search paths (":").
93 * See {@link #pathSeparatorChar}.
94 */
95 public static final String pathSeparator;
96
97 /**
98 * The path we return from getPath. This is almost the path we were
99 * given, but without duplicate adjacent slashes and without trailing
100 * slashes (except for the special case of the root directory). This
101 * path may be the empty string.
102 */
103 private String path;
104
105 /**
106 * The path we return from getAbsolutePath, and pass down to native code.
107 */
108 private String absolutePath;
109
110 static {
111 // The default protection domain grants access to these properties.
112 separatorChar = System.getProperty("file.separator", "/").charAt(0);
113 pathSeparatorChar = System.getProperty("path.separator", ":").charAt(0);
114 separator = String.valueOf(separatorChar);
115 pathSeparator = String.valueOf(pathSeparatorChar);
116 }
117
118 /**
119 * Constructs a new file using the specified directory and name.
120 *
121 * @param dir
122 * the directory where the file is stored.
123 * @param name
124 * the file's name.
125 * @throws NullPointerException
126 * if {@code name} is {@code null}.
127 */
128 public File(File dir, String name) {
129 this(dir == null ? null : dir.getPath(), name);
130 }
131
132 /**
133 * Constructs a new file using the specified path.
134 *
135 * @param path
136 * the path to be used for the file.
137 */
138 public File(String path) {
139 init(path);
140 }
141
142 /**
143 * Constructs a new File using the specified directory path and file name,
144 * placing a path separator between the two.
145 *
146 * @param dirPath
147 * the path to the directory where the file is stored.
148 * @param name
149 * the file's name.
150 * @throws NullPointerException
151 * if {@code name} is {@code null}.
152 */
153 public File(String dirPath, String name) {
154 if (name == null) {
155 throw new NullPointerException();
156 }
157 if (dirPath == null || dirPath.isEmpty()) {
158 init(name);
159 } else if (name.isEmpty()) {
160 init(dirPath);
161 } else {
162 init(join(dirPath, name));
163 }
164 }
165
166 /**
167 * Constructs a new File using the path of the specified URI. {@code uri}
168 * needs to be an absolute and hierarchical Unified Resource Identifier with
169 * file scheme and non-empty path component, but with undefined authority,
170 * query or fragment components.
171 *
172 * @param uri
173 * the Unified Resource Identifier that is used to construct this
174 * file.
175 * @throws IllegalArgumentException
176 * if {@code uri} does not comply with the conditions above.
177 * @see #toURI
178 * @see java.net.URI
179 */
180 public File(URI uri) {
181 // check pre-conditions
182 checkURI(uri);
183 init(uri.getPath());
184 }
185
186 private void init(String dirtyPath) {
187 // Cache the path and the absolute path.
188 // We can't call isAbsolute() here (http://b/2486943).
189 String cleanPath = fixSlashes(dirtyPath);
190 boolean isAbsolute = cleanPath.length() > 0 && cleanPath.charAt(0) == separatorChar;
191 if (isAbsolute) {
192 this.path = this.absolutePath = cleanPath;
193 } else {
194 String userDir = AccessController.doPrivileged(new PriviAction<String>("user.dir"));
195 this.absolutePath = cleanPath.isEmpty() ? userDir : join(userDir, cleanPath);
196 // We want path to be equal to cleanPath, but we'd like to reuse absolutePath's char[].
197 this.path = absolutePath.substring(absolutePath.length() - cleanPath.length());
198 }
199 }
200
201 // Removes duplicate adjacent slashes and any trailing slash.
202 private String fixSlashes(String origPath) {
203 // Remove duplicate adjacent slashes.
204 boolean lastWasSlash = false;
205 char[] newPath = origPath.toCharArray();
206 int length = newPath.length;
207 int newLength = 0;
208 for (int i = 0; i < length; ++i) {
209 char ch = newPath[i];
210 if (ch == '/') {
211 if (!lastWasSlash) {
212 newPath[newLength++] = separatorChar;
213 lastWasSlash = true;
214 }
215 } else {
216 newPath[newLength++] = ch;
217 lastWasSlash = false;
218 }
219 }
220 // Remove any trailing slash (unless this is the root of the file system).
221 if (lastWasSlash && newLength > 1) {
222 newLength--;
223 }
224 // Reuse the original string if possible.
225 return (newLength != length) ? new String(newPath, 0, newLength) : origPath;
226 }
227
228 // Joins two path components, adding a separator only if necessary.
229 private String join(String prefix, String suffix) {
230 int prefixLength = prefix.length();
231 boolean haveSlash = (prefixLength > 0 && prefix.charAt(prefixLength - 1) == separatorChar);
232 if (!haveSlash) {
233 haveSlash = (suffix.length() > 0 && suffix.charAt(0) == separatorChar);
234 }
235 return haveSlash ? (prefix + suffix) : (prefix + separatorChar + suffix);
236 }
237
238 private void checkURI(URI uri) {
239 if (!uri.isAbsolute()) {
240 throw new IllegalArgumentException("URI is not absolute: " + uri);
241 } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
242 throw new IllegalArgumentException("URI is not hierarchical: " + uri);
243 }
244 if (!"file".equals(uri.getScheme())) {
245 throw new IllegalArgumentException("Expected file scheme in URI: " + uri);
246 }
247 String rawPath = uri.getRawPath();
248 if (rawPath == null || rawPath.isEmpty()) {
249 throw new IllegalArgumentException("Expected non-empty path in URI: " + uri);
250 }
251 if (uri.getRawAuthority() != null) {
252 throw new IllegalArgumentException("Found authority in URI: " + uri);
253 }
254 if (uri.getRawQuery() != null) {
255 throw new IllegalArgumentException("Found query in URI: " + uri);
256 }
257 if (uri.getRawFragment() != null) {
258 throw new IllegalArgumentException("Found fragment in URI: " + uri);
259 }
260 }
261
262 /**
263 * Lists the file system roots. The Java platform may support zero or more
264 * file systems, each with its own platform-dependent root. Further, the
265 * canonical pathname of any file on the system will always begin with one
266 * of the returned file system roots.
267 *
268 * @return the array of file system roots.
269 */
270 public static File[] listRoots() {
271 return new File[] { new File("/") };
272 }
273
274 /**
275 * Tests whether or not this process is allowed to execute this file.
276 * Note that this is a best-effort result; the only way to be certain is
277 * to actually attempt the operation.
278 *
279 * @return {@code true} if this file can be executed, {@code false} otherwise.
280 * @throws SecurityException
281 * If a security manager exists and
282 * SecurityManager.checkExec(java.lang.String) disallows read
283 * permission to this file object
284 * @see java.lang.SecurityManager#checkExec(String)
285 *
286 * @since 1.6
287 */
288 public boolean canExecute() {
289 if (path.isEmpty()) {
290 return false;
291 }
292 SecurityManager security = System.getSecurityManager();
293 if (security != null) {
294 security.checkExec(path); // Seems bogus, but this is what the RI does.
295 }
296 return canExecuteImpl(absolutePath);
297 }
298 private static native boolean canExecuteImpl(String path);
299
300 /**
301 * Indicates whether the current context is allowed to read from this file.
302 *
303 * @return {@code true} if this file can be read, {@code false} otherwise.
304 * @throws SecurityException
305 * if a {@code SecurityManager} is installed and it denies the
306 * read request.
307 */
308 public boolean canRead() {
309 if (path.isEmpty()) {
310 return false;
311 }
312 SecurityManager security = System.getSecurityManager();
313 if (security != null) {
314 security.checkRead(path);
315 }
316 return canReadImpl(absolutePath);
317 }
318 private static native boolean canReadImpl(String path);
319
320 /**
321 * Indicates whether the current context is allowed to write to this file.
322 *
323 * @return {@code true} if this file can be written, {@code false}
324 * otherwise.
325 * @throws SecurityException
326 * if a {@code SecurityManager} is installed and it denies the
327 * write request.
328 */
329 public boolean canWrite() {
330 if (path.isEmpty()) {
331 return false;
332 }
333 SecurityManager security = System.getSecurityManager();
334 if (security != null) {
335 security.checkWrite(path);
336 }
337 return canWriteImpl(absolutePath);
338 }
339 private static native boolean canWriteImpl(String path);
340
341 /**
342 * Returns the relative sort ordering of the paths for this file and the
343 * file {@code another}. The ordering is platform dependent.
344 *
345 * @param another
346 * a file to compare this file to
347 * @return an int determined by comparing the two paths. Possible values are
348 * described in the Comparable interface.
349 * @see Comparable
350 */
351 public int compareTo(File another) {
352 return this.getPath().compareTo(another.getPath());
353 }
354
355 /**
356 * Deletes this file. Directories must be empty before they will be deleted.
357 *
358 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
359 * Callers must check the return value.
360 *
361 * @return {@code true} if this file was deleted, {@code false} otherwise.
362 * @throws SecurityException
363 * if a {@code SecurityManager} is installed and it denies the
364 * request.
365 * @see java.lang.SecurityManager#checkDelete
366 */
367 public boolean delete() {
368 if (path.isEmpty()) {
369 return false;
370 }
371 SecurityManager security = System.getSecurityManager();
372 if (security != null) {
373 security.checkDelete(path);
374 }
375 return deleteImpl(absolutePath);
376 }
377
378 private static native boolean deleteImpl(String path);
379
380 /**
381 * Schedules this file to be automatically deleted once the virtual machine
382 * terminates. This will only happen when the virtual machine terminates
383 * normally as described by the Java Language Specification section 12.9.
384 *
385 * @throws SecurityException
386 * if a {@code SecurityManager} is installed and it denies the
387 * request.
388 */
389 public void deleteOnExit() {
390 SecurityManager security = System.getSecurityManager();
391 if (security != null) {
392 security.checkDelete(path);
393 }
394 DeleteOnExit.getInstance().addFile(getAbsoluteName());
395 }
396
397 /**
398 * Compares {@code obj} to this file and returns {@code true} if they
399 * represent the <em>same</em> object using a path specific comparison.
400 *
401 * @param obj
402 * the object to compare this file with.
403 * @return {@code true} if {@code obj} is the same as this object,
404 * {@code false} otherwise.
405 */
406 @Override
407 public boolean equals(Object obj) {
408 if (!(obj instanceof File)) {
409 return false;
410 }
411 return path.equals(((File) obj).getPath());
412 }
413
414 /**
415 * Returns a boolean indicating whether this file can be found on the
416 * underlying file system.
417 *
418 * @return {@code true} if this file exists, {@code false} otherwise.
419 * @throws SecurityException
420 * if a {@code SecurityManager} is installed and it denies read
421 * access to this file.
422 * @see #getPath
423 * @see java.lang.SecurityManager#checkRead(FileDescriptor)
424 */
425 public boolean exists() {
426 if (path.isEmpty()) {
427 return false;
428 }
429 SecurityManager security = System.getSecurityManager();
430 if (security != null) {
431 security.checkRead(path);
432 }
433 return existsImpl(absolutePath);
434 }
435
436 private static native boolean existsImpl(String path);
437
438 /**
439 * Returns the absolute path of this file.
440 *
441 * @return the absolute file path.
442 */
443 public String getAbsolutePath() {
444 return absolutePath;
445 }
446
447 /**
448 * Returns a new file constructed using the absolute path of this file.
449 *
450 * @return a new file from this file's absolute path.
451 * @see java.lang.SecurityManager#checkPropertyAccess
452 */
453 public File getAbsoluteFile() {
454 return new File(this.getAbsolutePath());
455 }
456
457 /**
458 * Returns the absolute path of this file with all references resolved. An
459 * <em>absolute</em> path is one that begins at the root of the file
460 * system. The canonical path is one in which all references have been
461 * resolved. For the cases of '..' and '.', where the file system supports
462 * parent and working directory respectively, these are removed and replaced
463 * with a direct directory reference. If the file does not exist,
464 * getCanonicalPath() may not resolve any references and simply returns an
465 * absolute path name or throws an IOException.
466 *
467 * @return the canonical path of this file.
468 * @throws IOException
469 * if an I/O error occurs.
470 */
471 public String getCanonicalPath() throws IOException {
472 // BEGIN android-removed
473 // Caching the canonical path is bogus. Users facing specific
474 // performance problems can perform their own caching, with
475 // eviction strategies that are appropriate for their application.
476 // A VM-wide cache with no mechanism to evict stale elements is a
477 // disservice to applications that need up-to-date data.
478 // String canonPath = FileCanonPathCache.get(absPath);
479 // if (canonPath != null) {
480 // return canonPath;
481 // }
482 // END android-removed
483
484 // TODO: rewrite getCanonicalPath, resolve, and resolveLink.
485
486 String result = absolutePath;
487 if (separatorChar == '/') {
488 // resolve the full path first
489 result = resolveLink(result, result.length(), false);
490 // resolve the parent directories
491 result = resolve(result);
492 }
493 int numSeparators = 1;
494 for (int i = 0; i < result.length(); ++i) {
495 if (result.charAt(i) == separatorChar) {
496 numSeparators++;
497 }
498 }
499 int[] sepLocations = new int[numSeparators];
500 int rootLoc = 0;
501 if (separatorChar != '/') {
502 if (result.charAt(0) == '\\') {
503 rootLoc = (result.length() > 1 && result.charAt(1) == '\\') ? 1 : 0;
504 } else {
505 rootLoc = 2; // skip drive i.e. c:
506 }
507 }
508
509 char[] newResult = new char[result.length() + 1];
510 int newLength = 0, lastSlash = 0, foundDots = 0;
511 sepLocations[lastSlash] = rootLoc;
512 for (int i = 0; i <= result.length(); ++i) {
513 if (i < rootLoc) {
514 newResult[newLength++] = result.charAt(i);
515 } else {
516 if (i == result.length() || result.charAt(i) == separatorChar) {
517 if (i == result.length() && foundDots == 0) {
518 break;
519 }
520 if (foundDots == 1) {
521 /* Don't write anything, just reset and continue */
522 foundDots = 0;
523 continue;
524 }
525 if (foundDots > 1) {
526 /* Go back N levels */
527 lastSlash = lastSlash > (foundDots - 1) ? lastSlash - (foundDots - 1) : 0;
528 newLength = sepLocations[lastSlash] + 1;
529 foundDots = 0;
530 continue;
531 }
532 sepLocations[++lastSlash] = newLength;
533 newResult[newLength++] = separatorChar;
534 continue;
535 }
536 if (result.charAt(i) == '.') {
537 foundDots++;
538 continue;
539 }
540 /* Found some dots within text, write them out */
541 if (foundDots > 0) {
542 for (int j = 0; j < foundDots; j++) {
543 newResult[newLength++] = '.';
544 }
545 }
546 newResult[newLength++] = result.charAt(i);
547 foundDots = 0;
548 }
549 }
550 // remove trailing slash
551 if (newLength > (rootLoc + 1) && newResult[newLength - 1] == separatorChar) {
552 newLength--;
553 }
554 return new String(newResult, 0, newLength);
555 }
556
557 /*
558 * Resolve symbolic links in the parent directories.
559 */
560 private static String resolve(String path) throws IOException {
561 int last = 1;
562 String linkPath = path;
563 String bytes;
564 boolean done;
565 for (int i = 1; i <= path.length(); i++) {
566 if (i == path.length() || path.charAt(i) == separatorChar) {
567 done = i >= path.length() - 1;
568 // if there is only one segment, do nothing
569 if (done && linkPath.length() == 1) {
570 return path;
571 }
572 boolean inPlace = false;
573 if (linkPath.equals(path)) {
574 bytes = path;
575 // if there are no symbolic links, truncate the path instead of copying
576 if (!done) {
577 inPlace = true;
578 path = path.substring(0, i);
579 }
580 } else {
581 int nextSize = i - last + 1;
582 int linkSize = linkPath.length();
583 if (linkPath.charAt(linkSize - 1) == separatorChar) {
584 linkSize--;
585 }
586 bytes = linkPath.substring(0, linkSize) +
587 path.substring(last - 1, last - 1 + nextSize);
588 // the full path has already been resolved
589 }
590 if (done) {
591 return bytes;
592 }
593 linkPath = resolveLink(bytes, inPlace ? i : bytes.length(), true);
594 if (inPlace) {
595 // path[i] = '/';
596 path = path.substring(0, i) + '/' + (i + 1 < path.length() ? path.substring(i + 1) : "");
597 }
598 last = i + 1;
599 }
600 }
601 throw new InternalError();
602 }
603
604 /*
605 * Resolve a symbolic link. While the path resolves to an existing path,
606 * keep resolving. If an absolute link is found, resolve the parent
607 * directories if resolveAbsolute is true.
608 */
609 private static String resolveLink(String path, int length, boolean resolveAbsolute) throws IOException {
610 boolean restart = false;
611 do {
612 String fragment = path.substring(0, length);
613 String target = readlink(fragment);
614 if (target.equals(fragment)) {
615 break;
616 }
617 if (target.charAt(0) == separatorChar) {
618 // The link target was an absolute path, so we may need to start again.
619 restart = resolveAbsolute;
620 path = target + path.substring(length);
621 } else {
622 path = path.substring(0, path.lastIndexOf(separatorChar, length - 1) + 1) + target;
623 }
624 length = path.length();
625 } while (existsImpl(path));
626 // resolve the parent directories
627 if (restart) {
628 return resolve(path);
629 }
630 return path;
631 }
632
633 private static native String readlink(String filePath);
634
635 /**
636 * Returns a new file created using the canonical path of this file.
637 * Equivalent to {@code new File(this.getCanonicalPath())}.
638 *
639 * @return the new file constructed from this file's canonical path.
640 * @throws IOException
641 * if an I/O error occurs.
642 * @see java.lang.SecurityManager#checkPropertyAccess
643 */
644 public File getCanonicalFile() throws IOException {
645 return new File(getCanonicalPath());
646 }
647
648 /**
649 * Returns the name of the file or directory represented by this file.
650 *
651 * @return this file's name or an empty string if there is no name part in
652 * the file's path.
653 */
654 public String getName() {
655 int separatorIndex = path.lastIndexOf(separator);
656 return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
657 }
658
659 /**
660 * Returns the pathname of the parent of this file. This is the path up to
661 * but not including the last name. {@code null} is returned if there is no
662 * parent.
663 *
664 * @return this file's parent pathname or {@code null}.
665 */
666 public String getParent() {
667 int length = path.length(), firstInPath = 0;
668 if (separatorChar == '\\' && length > 2 && path.charAt(1) == ':') {
669 firstInPath = 2;
670 }
671 int index = path.lastIndexOf(separatorChar);
672 if (index == -1 && firstInPath > 0) {
673 index = 2;
674 }
675 if (index == -1 || path.charAt(length - 1) == separatorChar) {
676 return null;
677 }
678 if (path.indexOf(separatorChar) == index
679 && path.charAt(firstInPath) == separatorChar) {
680 return path.substring(0, index + 1);
681 }
682 return path.substring(0, index);
683 }
684
685 /**
686 * Returns a new file made from the pathname of the parent of this file.
687 * This is the path up to but not including the last name. {@code null} is
688 * returned when there is no parent.
689 *
690 * @return a new file representing this file's parent or {@code null}.
691 */
692 public File getParentFile() {
693 String tempParent = getParent();
694 if (tempParent == null) {
695 return null;
696 }
697 return new File(tempParent);
698 }
699
700 /**
701 * Returns the path of this file.
702 *
703 * @return this file's path.
704 */
705 public String getPath() {
706 return path;
707 }
708
709 /**
710 * Returns an integer hash code for the receiver. Any two objects for which
711 * {@code equals} returns {@code true} must return the same hash code.
712 *
713 * @return this files's hash value.
714 * @see #equals
715 */
716 @Override
717 public int hashCode() {
718 return getPath().hashCode() ^ 1234321;
719 }
720
721 /**
722 * Indicates if this file's pathname is absolute. Whether a pathname is
723 * absolute is platform specific. On Android, absolute paths start with
724 * the character '/'.
725 *
726 * @return {@code true} if this file's pathname is absolute, {@code false}
727 * otherwise.
728 * @see #getPath
729 */
730 public boolean isAbsolute() {
731 return path.length() > 0 && path.charAt(0) == separatorChar;
732 }
733
734 /**
735 * Indicates if this file represents a <em>directory</em> on the
736 * underlying file system.
737 *
738 * @return {@code true} if this file is a directory, {@code false}
739 * otherwise.
740 * @throws SecurityException
741 * if a {@code SecurityManager} is installed and it denies read
742 * access to this file.
743 */
744 public boolean isDirectory() {
745 if (path.isEmpty()) {
746 return false;
747 }
748 SecurityManager security = System.getSecurityManager();
749 if (security != null) {
750 security.checkRead(path);
751 }
752 return isDirectoryImpl(absolutePath);
753 }
754
755 private static native boolean isDirectoryImpl(String path);
756
757 /**
758 * Indicates if this file represents a <em>file</em> on the underlying
759 * file system.
760 *
761 * @return {@code true} if this file is a file, {@code false} otherwise.
762 * @throws SecurityException
763 * if a {@code SecurityManager} is installed and it denies read
764 * access to this file.
765 */
766 public boolean isFile() {
767 if (path.isEmpty()) {
768 return false;
769 }
770 SecurityManager security = System.getSecurityManager();
771 if (security != null) {
772 security.checkRead(path);
773 }
774 return isFileImpl(absolutePath);
775 }
776
777 private static native boolean isFileImpl(String path);
778
779 /**
780 * Returns whether or not this file is a hidden file as defined by the
781 * operating system. The notion of "hidden" is system-dependent. For Unix
782 * systems a file is considered hidden if its name starts with a ".". For
783 * Windows systems there is an explicit flag in the file system for this
784 * purpose.
785 *
786 * @return {@code true} if the file is hidden, {@code false} otherwise.
787 * @throws SecurityException
788 * if a {@code SecurityManager} is installed and it denies read
789 * access to this file.
790 */
791 public boolean isHidden() {
792 if (path.isEmpty()) {
793 return false;
794 }
795 SecurityManager security = System.getSecurityManager();
796 if (security != null) {
797 security.checkRead(path);
798 }
799 return getName().startsWith(".");
800 }
801
802 /**
803 * Returns the time when this file was last modified, measured in
804 * milliseconds since January 1st, 1970, midnight.
805 * Returns 0 if the file does not exist.
806 *
807 * @return the time when this file was last modified.
808 * @throws SecurityException
809 * if a {@code SecurityManager} is installed and it denies read
810 * access to this file.
811 */
812 public long lastModified() {
813 if (path.isEmpty()) {
814 return 0;
815 }
816 SecurityManager security = System.getSecurityManager();
817 if (security != null) {
818 security.checkRead(path);
819 }
820 return lastModifiedImpl(absolutePath);
821 }
822
823 private static native long lastModifiedImpl(String path);
824
825 /**
826 * Sets the time this file was last modified, measured in milliseconds since
827 * January 1st, 1970, midnight.
828 *
829 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
830 * Callers must check the return value.
831 *
832 * @param time
833 * the last modification time for this file.
834 * @return {@code true} if the operation is successful, {@code false}
835 * otherwise.
836 * @throws IllegalArgumentException
837 * if {@code time < 0}.
838 * @throws SecurityException
839 * if a {@code SecurityManager} is installed and it denies write
840 * access to this file.
841 */
842 public boolean setLastModified(long time) {
843 if (path.isEmpty()) {
844 return false;
845 }
846 if (time < 0) {
847 throw new IllegalArgumentException("time < 0");
848 }
849 SecurityManager security = System.getSecurityManager();
850 if (security != null) {
851 security.checkWrite(path);
852 }
853 return setLastModifiedImpl(absolutePath, time);
854 }
855
856 private static native boolean setLastModifiedImpl(String path, long time);
857
858 /**
859 * Equivalent to setWritable(false, false).
860 *
861 * @see #setWritable(boolean, boolean)
862 */
863 public boolean setReadOnly() {
864 return setWritable(false, false);
865 }
866
867 /**
868 * Manipulates the execute permissions for the abstract path designated by
869 * this file.
870 *
871 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
872 * Callers must check the return value.
873 *
874 * @param executable
875 * To allow execute permission if true, otherwise disallow
876 * @param ownerOnly
877 * To manipulate execute permission only for owner if true,
878 * otherwise for everyone. The manipulation will apply to
879 * everyone regardless of this value if the underlying system
880 * does not distinguish owner and other users.
881 * @return true if and only if the operation succeeded. If the user does not
882 * have permission to change the access permissions of this abstract
883 * pathname the operation will fail. If the underlying file system
884 * does not support execute permission and the value of executable
885 * is false, this operation will fail.
886 * @throws SecurityException -
887 * If a security manager exists and
888 * SecurityManager.checkWrite(java.lang.String) disallows write
889 * permission to this file object
890 * @since 1.6
891 */
892 public boolean setExecutable(boolean executable, boolean ownerOnly) {
893 if (path.isEmpty()) {
894 return false;
895 }
896 SecurityManager security = System.getSecurityManager();
897 if (security != null) {
898 security.checkWrite(path);
899 }
900 return setExecutableImpl(absolutePath, executable, ownerOnly);
901 }
902
903 /**
904 * Equivalent to setExecutable(executable, true).
905 * @see #setExecutable(boolean, boolean)
906 * @since 1.6
907 */
908 public boolean setExecutable(boolean executable) {
909 return setExecutable(executable, true);
910 }
911
912 private static native boolean setExecutableImpl(String path, boolean executable, boolean ownerOnly);
913
914 /**
915 * Manipulates the read permissions for the abstract path designated by this
916 * file.
917 *
918 * @param readable
919 * To allow read permission if true, otherwise disallow
920 * @param ownerOnly
921 * To manipulate read permission only for owner if true,
922 * otherwise for everyone. The manipulation will apply to
923 * everyone regardless of this value if the underlying system
924 * does not distinguish owner and other users.
925 * @return true if and only if the operation succeeded. If the user does not
926 * have permission to change the access permissions of this abstract
927 * pathname the operation will fail. If the underlying file system
928 * does not support read permission and the value of readable is
929 * false, this operation will fail.
930 * @throws SecurityException -
931 * If a security manager exists and
932 * SecurityManager.checkWrite(java.lang.String) disallows write
933 * permission to this file object
934 * @since 1.6
935 */
936 public boolean setReadable(boolean readable, boolean ownerOnly) {
937 if (path.isEmpty()) {
938 return false;
939 }
940 SecurityManager security = System.getSecurityManager();
941 if (security != null) {
942 security.checkWrite(path);
943 }
944 return setReadableImpl(absolutePath, readable, ownerOnly);
945 }
946
947 /**
948 * Equivalent to setReadable(readable, true).
949 * @see #setReadable(boolean, boolean)
950 * @since 1.6
951 */
952 public boolean setReadable(boolean readable) {
953 return setReadable(readable, true);
954 }
955
956 private static native boolean setReadableImpl(String path, boolean readable, boolean ownerOnly);
957
958 /**
959 * Manipulates the write permissions for the abstract path designated by this
960 * file.
961 *
962 * @param writable
963 * To allow write permission if true, otherwise disallow
964 * @param ownerOnly
965 * To manipulate write permission only for owner if true,
966 * otherwise for everyone. The manipulation will apply to
967 * everyone regardless of this value if the underlying system
968 * does not distinguish owner and other users.
969 * @return true if and only if the operation succeeded. If the user does not
970 * have permission to change the access permissions of this abstract
971 * pathname the operation will fail.
972 * @throws SecurityException -
973 * If a security manager exists and
974 * SecurityManager.checkWrite(java.lang.String) disallows write
975 * permission to this file object
976 * @since 1.6
977 */
978 public boolean setWritable(boolean writable, boolean ownerOnly) {
979 if (path.isEmpty()) {
980 return false;
981 }
982 SecurityManager security = System.getSecurityManager();
983 if (security != null) {
984 security.checkWrite(path);
985 }
986 return setWritableImpl(absolutePath, writable, ownerOnly);
987 }
988
989 /**
990 * Equivalent to setWritable(writable, true).
991 * @see #setWritable(boolean, boolean)
992 * @since 1.6
993 */
994 public boolean setWritable(boolean writable) {
995 return setWritable(writable, true);
996 }
997
998 private static native boolean setWritableImpl(String path, boolean writable, boolean ownerOnly);
999
1000 /**
1001 * Returns the length of this file in bytes.
1002 * Returns 0 if the file does not exist.
1003 * The result for a directory is not defined.
1004 *
1005 * @return the number of bytes in this file.
1006 * @throws SecurityException
1007 * if a {@code SecurityManager} is installed and it denies read
1008 * access to this file.
1009 */
1010 public long length() {
1011 SecurityManager security = System.getSecurityManager();
1012 if (security != null) {
1013 security.checkRead(path);
1014 }
1015 return lengthImpl(absolutePath);
1016 }
1017
1018 private static native long lengthImpl(String path);
1019
1020 /**
1021 * Returns an array of strings with the file names in the directory
1022 * represented by this file. The result is {@code null} if this file is not
1023 * a directory.
1024 * <p>
1025 * The entries {@code .} and {@code ..} representing the current and parent
1026 * directory are not returned as part of the list.
1027 *
1028 * @return an array of strings with file names or {@code null}.
1029 * @throws SecurityException
1030 * if a {@code SecurityManager} is installed and it denies read
1031 * access to this file.
1032 * @see #isDirectory
1033 * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1034 */
1035 public String[] list() {
1036 SecurityManager security = System.getSecurityManager();
1037 if (security != null) {
1038 security.checkRead(path);
1039 }
1040 if (path.isEmpty()) {
1041 return null;
1042 }
1043 return listImpl(absolutePath);
1044 }
1045
1046 private static native String[] listImpl(String path);
1047
1048 /**
1049 * Gets a list of the files in the directory represented by this file. This
1050 * list is then filtered through a FilenameFilter and the names of files
1051 * with matching names are returned as an array of strings. Returns
1052 * {@code null} if this file is not a directory. If {@code filter} is
1053 * {@code null} then all filenames match.
1054 * <p>
1055 * The entries {@code .} and {@code ..} representing the current and parent
1056 * directories are not returned as part of the list.
1057 *
1058 * @param filter
1059 * the filter to match names against, may be {@code null}.
1060 * @return an array of files or {@code null}.
1061 * @throws SecurityException
1062 * if a {@code SecurityManager} is installed and it denies read
1063 * access to this file.
1064 * @see #getPath
1065 * @see #isDirectory
1066 * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1067 */
1068 public String[] list(FilenameFilter filter) {
1069 String[] filenames = list();
1070 if (filter == null || filenames == null) {
1071 return filenames;
1072 }
1073 List<String> result = new ArrayList<String>(filenames.length);
1074 for (String filename : filenames) {
1075 if (filter.accept(this, filename)) {
1076 result.add(filename);
1077 }
1078 }
1079 return result.toArray(new String[result.size()]);
1080 }
1081
1082 /**
1083 * Returns an array of files contained in the directory represented by this
1084 * file. The result is {@code null} if this file is not a directory. The
1085 * paths of the files in the array are absolute if the path of this file is
1086 * absolute, they are relative otherwise.
1087 *
1088 * @return an array of files or {@code null}.
1089 * @throws SecurityException
1090 * if a {@code SecurityManager} is installed and it denies read
1091 * access to this file.
1092 * @see #list
1093 * @see #isDirectory
1094 */
1095 public File[] listFiles() {
1096 return filenamesToFiles(list());
1097 }
1098
1099 /**
1100 * Gets a list of the files in the directory represented by this file. This
1101 * list is then filtered through a FilenameFilter and files with matching
1102 * names are returned as an array of files. Returns {@code null} if this
1103 * file is not a directory. If {@code filter} is {@code null} then all
1104 * filenames match.
1105 * <p>
1106 * The entries {@code .} and {@code ..} representing the current and parent
1107 * directories are not returned as part of the list.
1108 *
1109 * @param filter
1110 * the filter to match names against, may be {@code null}.
1111 * @return an array of files or {@code null}.
1112 * @throws SecurityException
1113 * if a {@code SecurityManager} is installed and it denies read
1114 * access to this file.
1115 * @see #list(FilenameFilter filter)
1116 * @see #getPath
1117 * @see #isDirectory
1118 * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1119 */
1120 public File[] listFiles(FilenameFilter filter) {
1121 return filenamesToFiles(list(filter));
1122 }
1123
1124 /**
1125 * Gets a list of the files in the directory represented by this file. This
1126 * list is then filtered through a FileFilter and matching files are
1127 * returned as an array of files. Returns {@code null} if this file is not a
1128 * directory. If {@code filter} is {@code null} then all files match.
1129 * <p>
1130 * The entries {@code .} and {@code ..} representing the current and parent
1131 * directories are not returned as part of the list.
1132 *
1133 * @param filter
1134 * the filter to match names against, may be {@code null}.
1135 * @return an array of files or {@code null}.
1136 * @throws SecurityException
1137 * if a {@code SecurityManager} is installed and it denies read
1138 * access to this file.
1139 * @see #getPath
1140 * @see #isDirectory
1141 * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1142 */
1143 public File[] listFiles(FileFilter filter) {
1144 File[] files = listFiles();
1145 if (filter == null || files == null) {
1146 return files;
1147 }
1148 List<File> result = new ArrayList<File>(files.length);
1149 for (File file : files) {
1150 if (filter.accept(file)) {
1151 result.add(file);
1152 }
1153 }
1154 return result.toArray(new File[result.size()]);
1155 }
1156
1157 /**
1158 * Converts a String[] containing filenames to a File[].
1159 * Note that the filenames must not contain slashes.
1160 * This method is to remove duplication in the implementation
1161 * of File.list's overloads.
1162 */
1163 private File[] filenamesToFiles(String[] filenames) {
1164 if (filenames == null) {
1165 return null;
1166 }
1167 int count = filenames.length;
1168 File[] result = new File[count];
1169 for (int i = 0; i < count; ++i) {
1170 result[i] = new File(this, filenames[i]);
1171 }
1172 return result;
1173 }
1174
1175 /**
1176 * Creates the directory named by the trailing filename of this file. Does
1177 * not create the complete path required to create this directory.
1178 *
1179 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
1180 * Callers must check the return value.
1181 *
1182 * @return {@code true} if the directory has been created, {@code false}
1183 * otherwise.
1184 * @throws SecurityException
1185 * if a {@code SecurityManager} is installed and it denies write
1186 * access for this file.
1187 * @see #mkdirs
1188 */
1189 public boolean mkdir() {
1190 SecurityManager security = System.getSecurityManager();
1191 if (security != null) {
1192 security.checkWrite(path);
1193 }
1194 return mkdirImpl(absolutePath);
1195 }
1196
1197 private static native boolean mkdirImpl(String path);
1198
1199 /**
1200 * Creates the directory named by the trailing filename of this file,
1201 * including the complete directory path required to create this directory.
1202 *
1203 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
1204 * Callers must check the return value.
1205 *
1206 * @return {@code true} if the necessary directories have been created,
1207 * {@code false} if the target directory already exists or one of
1208 * the directories can not be created.
1209 * @throws SecurityException
1210 * if a {@code SecurityManager} is installed and it denies write
1211 * access for this file.
1212 * @see #mkdir
1213 */
1214 public boolean mkdirs() {
1215 /* If the terminal directory already exists, answer false */
1216 if (exists()) {
1217 return false;
1218 }
1219
1220 /* If the receiver can be created, answer true */
1221 if (mkdir()) {
1222 return true;
1223 }
1224
1225 String parentDir = getParent();
1226 /* If there is no parent and we were not created, answer false */
1227 if (parentDir == null) {
1228 return false;
1229 }
1230
1231 /* Otherwise, try to create a parent directory and then this directory */
1232 return (new File(parentDir).mkdirs() && mkdir());
1233 }
1234
1235 /**
1236 * Creates a new, empty file on the file system according to the path
1237 * information stored in this file.
1238 *
1239 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
1240 * Callers must check the return value.
1241 *
1242 * @return {@code true} if the file has been created, {@code false} if it
1243 * already exists.
1244 * @throws IOException if it's not possible to create the file.
1245 * @throws SecurityException
1246 * if a {@code SecurityManager} is installed and it denies write
1247 * access for this file.
1248 */
1249 public boolean createNewFile() throws IOException {
1250 SecurityManager security = System.getSecurityManager();
1251 if (security != null) {
1252 security.checkWrite(path);
1253 }
1254 if (path.isEmpty()) {
1255 throw new IOException("No such file or directory");
1256 }
1257 return createNewFileImpl(absolutePath);
1258 }
1259
1260 private static native boolean createNewFileImpl(String path);
1261
1262 /**
1263 * Creates an empty temporary file using the given prefix and suffix as part
1264 * of the file name. If {@code suffix} is null, {@code .tmp} is used. This
1265 * method is a convenience method that calls
1266 * {@link #createTempFile(String, String, File)} with the third argument
1267 * being {@code null}.
1268 *
1269 * @param prefix
1270 * the prefix to the temp file name.
1271 * @param suffix
1272 * the suffix to the temp file name.
1273 * @return the temporary file.
1274 * @throws IOException
1275 * if an error occurs when writing the file.
1276 */
1277 public static File createTempFile(String prefix, String suffix) throws IOException {
1278 return createTempFile(prefix, suffix, null);
1279 }
1280
1281 /**
1282 * Creates an empty temporary file in the given directory using the given
1283 * prefix and suffix as part of the file name. If {@code suffix} is null, {@code .tmp} is used.
1284 *
1285 * <p>Note that this method does <i>not</i> call {@link #deleteOnExit}.
1286 *
1287 * @param prefix
1288 * the prefix to the temp file name.
1289 * @param suffix
1290 * the suffix to the temp file name.
1291 * @param directory
1292 * the location to which the temp file is to be written, or
1293 * {@code null} for the default location for temporary files,
1294 * which is taken from the "java.io.tmpdir" system property. It
1295 * may be necessary to set this property to an existing, writable
1296 * directory for this method to work properly.
1297 * @return the temporary file.
1298 * @throws IllegalArgumentException
1299 * if the length of {@code prefix} is less than 3.
1300 * @throws IOException
1301 * if an error occurs when writing the file.
1302 */
1303 @SuppressWarnings("nls")
1304 public static File createTempFile(String prefix, String suffix,
1305 File directory) throws IOException {
1306 // Force a prefix null check first
1307 if (prefix.length() < 3) {
1308 throw new IllegalArgumentException("prefix must be at least 3 characters");
1309 }
1310 if (suffix == null) {
1311 suffix = ".tmp";
1312 }
1313 File tmpDirFile = directory;
1314 if (tmpDirFile == null) {
1315 String tmpDir = AccessController.doPrivileged(
1316 new PriviAction<String>("java.io.tmpdir", "."));
1317 tmpDirFile = new File(tmpDir);
1318 }
1319 File result;
1320 do {
1321 result = new File(tmpDirFile, prefix + new Random().nextInt() + suffix);
1322 } while (!result.createNewFile());
1323 return result;
1324 }
1325
1326 /**
1327 * Renames this file to {@code newPath}. This operation is supported for both
1328 * files and directories.
1329 *
1330 * <p>Many failures are possible. Some of the more likely failures include:
1331 * <ul>
1332 * <li>Write permission is required on the directories containing both the source and
1333 * destination paths.
1334 * <li>Search permission is required for all parents of both paths.
1335 * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
1336 * this restriction when attempting to copy between internal storage and an SD card.
1337 * </ul>
1338 *
1339 * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
1340 * Callers must check the return value.
1341 *
1342 * @param newPath the new path.
1343 * @return true on success.
1344 * @throws SecurityException
1345 * if a {@code SecurityManager} is installed and it denies write
1346 * access for this file or {@code newPath}.
1347 */
1348 public boolean renameTo(File newPath) {
1349 if (path.isEmpty() || newPath.path.isEmpty()) {
1350 return false;
1351 }
1352 SecurityManager security = System.getSecurityManager();
1353 if (security != null) {
1354 security.checkWrite(path);
1355 security.checkWrite(newPath.path);
1356 }
1357 return renameToImpl(absolutePath, newPath.absolutePath);
1358 }
1359
1360 private static native boolean renameToImpl(String oldPath, String newPath);
1361
1362 /**
1363 * Returns a string containing a concise, human-readable description of this
1364 * file.
1365 *
1366 * @return a printable representation of this file.
1367 */
1368 @Override
1369 public String toString() {
1370 return path;
1371 }
1372
1373 /**
1374 * Returns a Uniform Resource Identifier for this file. The URI is system
1375 * dependent and may not be transferable between different operating / file
1376 * systems.
1377 *
1378 * @return an URI for this file.
1379 */
1380 @SuppressWarnings("nls")
1381 public URI toURI() {
1382 String name = getAbsoluteName();
1383 try {
1384 if (!name.startsWith("/")) {
1385 // start with sep.
1386 return new URI("file", null, new StringBuilder(
1387 name.length() + 1).append('/').append(name).toString(),
1388 null, null);
1389 } else if (name.startsWith("//")) {
1390 return new URI("file", "", name, null); // UNC path
1391 }
1392 return new URI("file", null, name, null, null);
1393 } catch (URISyntaxException e) {
1394 // this should never happen
1395 return null;
1396 }
1397 }
1398
1399 /**
1400 * Returns a Uniform Resource Locator for this file. The URL is system
1401 * dependent and may not be transferable between different operating / file
1402 * systems.
1403 *
1404 * @return a URL for this file.
1405 * @throws java.net.MalformedURLException
1406 * if the path cannot be transformed into a URL.
1407 * @deprecated use {@link #toURI} and {@link java.net.URI#toURL} to get
1408 * correct escaping of illegal characters.
1409 */
1410 @Deprecated
1411 @SuppressWarnings("nls")
1412 public URL toURL() throws java.net.MalformedURLException {
1413 String name = getAbsoluteName();
1414 if (!name.startsWith("/")) {
1415 // start with sep.
1416 return new URL("file", "", -1,
1417 new StringBuilder(name.length() + 1).append('/').append(name).toString(), null);
1418 } else if (name.startsWith("//")) {
1419 return new URL("file:" + name); // UNC path
1420 }
1421 return new URL("file", "", -1, name, null);
1422 }
1423
1424 private String getAbsoluteName() {
1425 File f = getAbsoluteFile();
1426 String name = f.getPath();
1427
1428 if (f.isDirectory() && name.charAt(name.length() - 1) != separatorChar) {
1429 // Directories must end with a slash
1430 name = new StringBuilder(name.length() + 1).append(name)
1431 .append('/').toString();
1432 }
1433 if (separatorChar != '/') { // Must convert slashes.
1434 name = name.replace(separatorChar, '/');
1435 }
1436 return name;
1437 }
1438
1439 private void writeObject(ObjectOutputStream stream) throws IOException {
1440 stream.defaultWriteObject();
1441 stream.writeChar(separatorChar);
1442 }
1443
1444 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1445 stream.defaultReadObject();
1446 char inSeparator = stream.readChar();
1447 init(path.replace(inSeparator, separatorChar));
1448 }
1449
1450 /**
1451 * Returns the total size in bytes of the partition containing this path.
1452 * Returns 0 if this path does not exist.
1453 *
1454 * @since 1.6
1455 */
1456 public long getTotalSpace() {
1457 SecurityManager security = System.getSecurityManager();
1458 if (security != null) {
1459 security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1460 }
1461 return getTotalSpaceImpl(absolutePath);
1462 }
1463 private static native long getTotalSpaceImpl(String path);
1464
1465 /**
1466 * Returns the number of usable free bytes on the partition containing this path.
1467 * Returns 0 if this path does not exist.
1468 *
1469 * <p>Note that this is likely to be an optimistic over-estimate and should not
1470 * be taken as a guarantee your application can actually write this many bytes.
1471 * On Android (and other Unix-based systems), this method returns the number of free bytes
1472 * available to non-root users, regardless of whether you're actually running as root,
1473 * and regardless of any quota or other restrictions that might apply to the user.
1474 * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
1475 *
1476 * @since 1.6
1477 */
1478 public long getUsableSpace() {
1479 SecurityManager security = System.getSecurityManager();
1480 if (security != null) {
1481 security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1482 }
1483 return getUsableSpaceImpl(absolutePath);
1484 }
1485 private static native long getUsableSpaceImpl(String path);
1486
1487 /**
1488 * Returns the number of free bytes on the partition containing this path.
1489 * Returns 0 if this path does not exist.
1490 *
1491 * <p>Note that this is likely to be an optimistic over-estimate and should not
1492 * be taken as a guarantee your application can actually write this many bytes.
1493 *
1494 * @since 1.6
1495 */
1496 public long getFreeSpace() {
1497 SecurityManager security = System.getSecurityManager();
1498 if (security != null) {
1499 security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1500 }
1501 return getFreeSpaceImpl(absolutePath);
1502 }
1503 private static native long getFreeSpaceImpl(String path);
1504}