Home | History | Annotate | Download | only in io
      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      */
    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 }
   1505