• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // 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 
28 package java.io;
29 
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.security.AccessController;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Random;
37 import org.apache.harmony.luni.util.DeleteOnExit;
38 import 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  */
62 public 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      */
File(File dir, String name)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      */
File(String path)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      */
File(String dirPath, String name)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      */
File(URI uri)180     public File(URI uri) {
181         // check pre-conditions
182         checkURI(uri);
183         init(uri.getPath());
184     }
185 
init(String dirtyPath)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.
fixSlashes(String origPath)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.
join(String prefix, String suffix)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 
checkURI(URI uri)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      */
listRoots()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      */
canExecute()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     }
canExecuteImpl(String path)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      */
canRead()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     }
canReadImpl(String path)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      */
canWrite()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     }
canWriteImpl(String path)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      */
compareTo(File another)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      */
delete()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 
deleteImpl(String path)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      */
deleteOnExit()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
equals(Object obj)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      */
exists()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 
existsImpl(String path)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      */
getAbsolutePath()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      */
getAbsoluteFile()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      */
getCanonicalPath()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      */
resolve(String path)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      */
resolveLink(String path, int length, boolean resolveAbsolute)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 
readlink(String filePath)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      */
getCanonicalFile()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      */
getName()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      */
getParent()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      */
getParentFile()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      */
getPath()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
hashCode()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      */
isAbsolute()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      */
isDirectory()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 
isDirectoryImpl(String path)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      */
isFile()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 
isFileImpl(String path)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      */
isHidden()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      */
lastModified()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 
lastModifiedImpl(String path)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      */
setLastModified(long time)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 
setLastModifiedImpl(String path, long time)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      */
setReadOnly()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      */
setExecutable(boolean executable, boolean ownerOnly)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      */
setExecutable(boolean executable)908     public boolean setExecutable(boolean executable) {
909         return setExecutable(executable, true);
910     }
911 
setExecutableImpl(String path, boolean executable, boolean ownerOnly)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      */
setReadable(boolean readable, boolean ownerOnly)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      */
setReadable(boolean readable)952     public boolean setReadable(boolean readable) {
953         return setReadable(readable, true);
954     }
955 
setReadableImpl(String path, boolean readable, boolean ownerOnly)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      */
setWritable(boolean writable, boolean ownerOnly)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      */
setWritable(boolean writable)994     public boolean setWritable(boolean writable) {
995         return setWritable(writable, true);
996     }
997 
setWritableImpl(String path, boolean writable, boolean ownerOnly)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      */
length()1010     public long length() {
1011         SecurityManager security = System.getSecurityManager();
1012         if (security != null) {
1013             security.checkRead(path);
1014         }
1015         return lengthImpl(absolutePath);
1016     }
1017 
lengthImpl(String path)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      */
list()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 
listImpl(String path)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      */
list(FilenameFilter filter)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      */
listFiles()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      */
listFiles(FilenameFilter filter)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      */
listFiles(FileFilter filter)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      */
filenamesToFiles(String[] filenames)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      */
mkdir()1189     public boolean mkdir() {
1190         SecurityManager security = System.getSecurityManager();
1191         if (security != null) {
1192             security.checkWrite(path);
1193         }
1194         return mkdirImpl(absolutePath);
1195     }
1196 
mkdirImpl(String path)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      */
mkdirs()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      */
createNewFile()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 
createNewFileImpl(String path)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      */
createTempFile(String prefix, String suffix)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")
createTempFile(String prefix, String suffix, File directory)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      */
renameTo(File newPath)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 
renameToImpl(String oldPath, String newPath)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
toString()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")
toURI()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")
toURL()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 
getAbsoluteName()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 
writeObject(ObjectOutputStream stream)1439     private void writeObject(ObjectOutputStream stream) throws IOException {
1440         stream.defaultWriteObject();
1441         stream.writeChar(separatorChar);
1442     }
1443 
readObject(ObjectInputStream stream)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      */
getTotalSpace()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     }
getTotalSpaceImpl(String path)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      */
getUsableSpace()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     }
getUsableSpaceImpl(String path)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      */
getFreeSpace()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     }
getFreeSpaceImpl(String path)1503     private static native long getFreeSpaceImpl(String path);
1504 }
1505