Frames | No Frames |
1: /* File.java -- Class representing a file on disk 2: Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.io; 41: 42: import java.net.MalformedURLException; 43: import java.net.URI; 44: import java.net.URISyntaxException; 45: import java.net.URL; 46: import gnu.classpath.Configuration; 47: 48: /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 49: * "The Java Language Specification", ISBN 0-201-63451-1 50: * Status: Complete to version 1.3. 51: */ 52: 53: /** 54: * This class represents a file or directory on a local disk. It provides 55: * facilities for dealing with a variety of systems that use various 56: * types of path separators ("/" versus "\", for example). It also 57: * contains method useful for creating and deleting files and directories. 58: * 59: * @author Aaron M. Renn (arenn@urbanophile.com) 60: * @author Tom Tromey (tromey@cygnus.com) 61: */ 62: public class File implements Serializable, Comparable 63: { 64: private static final long serialVersionUID = 301077366599181567L; 65: 66: // QUERY arguments to access function. 67: private final static int READ = 0; 68: private final static int WRITE = 1; 69: private final static int EXISTS = 2; 70: 71: // QUERY arguments to stat function. 72: private final static int DIRECTORY = 0; 73: private final static int ISFILE = 1; 74: private final static int ISHIDDEN = 2; 75: 76: // QUERY arguments to attr function. 77: private final static int MODIFIED = 0; 78: private final static int LENGTH = 1; 79: 80: private final native long attr (int query); 81: // On OSF1 V5.0, `stat' is a macro. It is easiest to use the name 82: // `_stat' instead. We do the same thing for `_access' just in 83: // case. 84: private final native boolean _access (int query); 85: private final native boolean _stat (int query); 86: 87: /** 88: * This is the path separator string for the current host. This field 89: * contains the value of the <code>file.separator</code> system property. 90: * An example separator string would be "/" on the GNU system. 91: */ 92: public static final String separator = System.getProperty("file.separator"); 93: private static final String dupSeparator = separator + separator; 94: 95: /** 96: * This is the first character of the file separator string. On many 97: * hosts (for example, on the GNU system), this represents the entire 98: * separator string. The complete separator string is obtained from the 99: * <code>file.separator</code>system property. 100: */ 101: public static final char separatorChar = separator.charAt(0); 102: 103: /** 104: * This is the string that is used to separate the host name from the 105: * path name in paths than include the host name. It is the value of 106: * the <code>path.separator</code> system property. 107: */ 108: public static final String pathSeparator 109: = System.getProperty("path.separator"); 110: 111: /** 112: * This is the first character of the string used to separate the host name 113: * from the path name in paths that include a host. The separator string 114: * is taken from the <code>path.separator</code> system property. 115: */ 116: public static final char pathSeparatorChar = pathSeparator.charAt(0); 117: 118: static final String tmpdir = System.getProperty("java.io.tmpdir"); 119: static int maxPathLen; 120: static boolean caseSensitive; 121: 122: static 123: { 124: if (Configuration.INIT_LOAD_LIBRARY) 125: { 126: System.loadLibrary("javaio"); 127: } 128: 129: init_native(); 130: } 131: 132: // Native function called at class initialization. This should should 133: // set the maxPathLen and caseSensitive variables. 134: private static native void init_native(); 135: 136: /** 137: * This is the path to the file set when the object is created. It 138: * may be an absolute or relative path name. 139: */ 140: private String path; 141: 142: // We keep a counter for use by createTempFile. We choose the first 143: // value randomly to try to avoid clashes with other VMs. 144: private static long counter = Double.doubleToLongBits (Math.random()); 145: 146: /** 147: * This method tests whether or not the current thread is allowed to 148: * to read the file pointed to by this object. This will be true if and 149: * and only if 1) the file exists and 2) the <code>SecurityManager</code> 150: * (if any) allows access to the file via it's <code>checkRead</code> 151: * method 3) the file is readable. 152: * 153: * @return <code>true</code> if reading is allowed, 154: * <code>false</code> otherwise 155: * 156: * @exception SecurityException If the <code>SecurityManager</code> 157: * does not allow access to the file 158: */ 159: public boolean canRead() 160: { 161: checkRead(); 162: return _access (READ); 163: } 164: 165: /** 166: * This method test whether or not the current thread is allowed to 167: * write to this object. This will be true if and only if 1) The 168: * <code>SecurityManager</code> (if any) allows write access to the 169: * file and 2) The file exists and 3) The file is writable. To determine 170: * whether or not a non-existent file can be created, check the parent 171: * directory for write access. 172: * 173: * @return <code>true</code> if writing is allowed, <code>false</code> 174: * otherwise 175: * 176: * @exception SecurityException If the <code>SecurityManager</code> 177: * does not allow access to the file 178: */ 179: public boolean canWrite() 180: { 181: checkWrite(); 182: return _access (WRITE); 183: } 184: 185: private native boolean performCreate() throws IOException; 186: 187: /** 188: * This method creates a new file of zero length with the same name as 189: * the path of this <code>File</code> object if an only if that file 190: * does not already exist. 191: * <p> 192: * A <code>SecurityManager.checkWrite</code> check is done prior 193: * to performing this action. 194: * 195: * @return <code>true</code> if the file was created, <code>false</code> if 196: * the file alread existed. 197: * 198: * @exception IOException If an I/O error occurs 199: * @exception SecurityException If the <code>SecurityManager</code> will 200: * not allow this operation to be performed. 201: * 202: * @since 1.2 203: */ 204: public boolean createNewFile() throws IOException 205: { 206: checkWrite(); 207: return performCreate(); 208: } 209: 210: /* 211: * This native method handles the actual deleting of the file 212: */ 213: private native boolean performDelete(); 214: 215: /** 216: * This method deletes the file represented by this object. If this file 217: * is a directory, it must be empty in order for the delete to succeed. 218: * 219: * @return <code>true</code> if the file was deleted, <code>false</code> 220: * otherwise 221: * 222: * @exception SecurityException If deleting of the file is not allowed 223: */ 224: public synchronized boolean delete() 225: { 226: SecurityManager s = System.getSecurityManager(); 227: 228: if (s != null) 229: s.checkDelete(path); 230: 231: return performDelete(); 232: } 233: 234: /** 235: * This method tests two <code>File</code> objects for equality by 236: * comparing the path of the specified <code>File</code> against the path 237: * of this object. The two objects are equal if an only if 1) The 238: * argument is not null 2) The argument is a <code>File</code> object and 239: * 3) The path of the <code>File</code>argument is equal to the path 240: * of this object. 241: * <p> 242: * The paths of the files are determined by calling the 243: * <code>getPath()</code> 244: * method on each object. 245: * 246: * @return <code>true</code> if the two objects are equal, 247: * <code>false</code> otherwise. 248: */ 249: public boolean equals(Object obj) 250: { 251: if (! (obj instanceof File)) 252: return false; 253: 254: File other = (File) obj; 255: 256: if (caseSensitive) 257: return path.equals(other.path); 258: else 259: return path.equalsIgnoreCase(other.path); 260: } 261: 262: /* 263: * This method tests whether or not the file represented by the 264: * object actually exists on the filesystem. 265: */ 266: private boolean internalExists() 267: { 268: return _access (EXISTS); 269: } 270: 271: /** 272: * This method tests whether or not the file represented by the object 273: * actually exists on the filesystem. 274: * 275: * @return <code>true</code> if the file exists, <code>false</code>otherwise. 276: * 277: * @exception SecurityException If reading of the file is not permitted 278: */ 279: public boolean exists() 280: { 281: checkRead(); 282: return internalExists(); 283: } 284: 285: /** 286: * This method initializes a new <code>File</code> object to represent 287: * a file with the specified path. 288: * 289: * @param name The path name of the file 290: */ 291: public File(String name) 292: { 293: path = normalizePath (name); 294: } 295: 296: // Remove duplicate and redundant separator characters. 297: private String normalizePath(String p) 298: { 299: // On Windows, convert any '/' to '\'. This appears to be the same logic 300: // that Sun's Win32 Java performs. 301: if (separatorChar == '\\') 302: { 303: p = p.replace ('/', '\\'); 304: // We have to special case the "\c:" prefix. 305: if (p.length() > 2 && p.charAt(0) == '\\' && 306: ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') || 307: (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) && 308: p.charAt(2) == ':') 309: p = p.substring(1); 310: } 311: 312: int dupIndex = p.indexOf(dupSeparator); 313: int plen = p.length(); 314: 315: // Special case: permit Windows UNC path prefix. 316: if (dupSeparator.equals("\\\\") && dupIndex == 0) 317: dupIndex = p.indexOf(dupSeparator, 1); 318: 319: if (dupIndex == -1) 320: { 321: // Ignore trailing separator (though on Windows "a:\", for 322: // example, is a valid and minimal path). 323: if (plen > 1 && p.charAt (plen - 1) == separatorChar) 324: { 325: if (! (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':')) 326: return p.substring (0, plen - 1); 327: } 328: else 329: return p; 330: } 331: 332: StringBuffer newpath = new StringBuffer(plen); 333: int last = 0; 334: while (dupIndex != -1) 335: { 336: newpath.append(p.substring(last, dupIndex)); 337: // Ignore the duplicate path characters. 338: while (p.charAt(dupIndex) == separatorChar) 339: { 340: dupIndex++; 341: if (dupIndex == plen) 342: return newpath.toString(); 343: } 344: newpath.append(separatorChar); 345: last = dupIndex; 346: dupIndex = p.indexOf(dupSeparator, last); 347: } 348: 349: // Again, ignore possible trailing separator (except special cases 350: // like "a:\" on Windows). 351: int end; 352: if (plen > 1 && p.charAt (plen - 1) == separatorChar) 353: { 354: if (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':') 355: end = plen; 356: else 357: end = plen - 1; 358: } 359: else 360: end = plen; 361: newpath.append(p.substring(last, end)); 362: 363: return newpath.toString(); 364: } 365: 366: /** 367: * This method initializes a new <code>File</code> object to represent 368: * a file in the specified named directory. The path name to the file 369: * will be the directory name plus the separator string plus the file 370: * name. If the directory path name ends in the separator string, another 371: * separator string will still be appended. 372: * 373: * @param dirPath The path to the directory the file resides in 374: * @param name The name of the file 375: */ 376: public File(String dirPath, String name) 377: { 378: if (name == null) 379: throw new NullPointerException(); 380: if (dirPath != null) 381: { 382: if (dirPath.length() > 0) 383: { 384: // Try to be smart about the number of separator characters. 385: if (dirPath.charAt(dirPath.length() - 1) == separatorChar 386: || name.length() == 0) 387: path = normalizePath(dirPath + name); 388: else 389: path = normalizePath(dirPath + separatorChar + name); 390: } 391: else 392: { 393: // If dirPath is empty, use a system dependant 394: // default prefix. 395: // Note that the leading separators in name have 396: // to be chopped off, to prevent them forming 397: // a UNC prefix on Windows. 398: if (separatorChar == '\\' /* TODO use ON_WINDOWS */) 399: { 400: int skip = 0; 401: while(name.length() > skip 402: && (name.charAt(skip) == separatorChar 403: || name.charAt(skip) == '/')) 404: { 405: skip++; 406: } 407: name = name.substring(skip); 408: } 409: path = normalizePath(separatorChar + name); 410: } 411: } 412: else 413: path = normalizePath(name); 414: } 415: 416: /** 417: * This method initializes a new <code>File</code> object to represent 418: * a file in the specified directory. If the <code>directory</code> 419: * argument is <code>null</code>, the file is assumed to be in the 420: * current directory as specified by the <code>user.dir</code> system 421: * property 422: * 423: * @param directory The directory this file resides in 424: * @param name The name of the file 425: */ 426: public File(File directory, String name) 427: { 428: this (directory == null ? null : directory.path, name); 429: } 430: 431: /** 432: * This method initializes a new <code>File</code> object to represent 433: * a file corresponding to the specified <code>file:</code> protocol URI. 434: * 435: * @param uri The uri. 436: */ 437: public File(URI uri) 438: { 439: if (uri == null) 440: throw new NullPointerException("uri is null"); 441: 442: if (!uri.getScheme().equals("file")) 443: throw new IllegalArgumentException("invalid uri protocol"); 444: 445: String name = uri.getPath(); 446: if (name == null) 447: throw new IllegalArgumentException("URI \"" + uri 448: + "\" is not hierarchical"); 449: path = normalizePath(name); 450: } 451: 452: /** 453: * This method returns the path of this file as an absolute path name. 454: * If the path name is already absolute, then it is returned. Otherwise 455: * the value returned is the current directory plus the separatory 456: * string plus the path of the file. The current directory is determined 457: * from the <code>user.dir</code> system property. 458: * 459: * @return The absolute path of this file 460: */ 461: public String getAbsolutePath() 462: { 463: if (isAbsolute()) 464: return path; 465: else if (separatorChar == '\\' 466: && path.length() > 0 && path.charAt (0) == '\\') 467: { 468: // On Windows, even if the path starts with a '\\' it is not 469: // really absolute until we prefix the drive specifier from 470: // the current working directory to it. 471: return System.getProperty ("user.dir").substring (0, 2) + path; 472: } 473: else if (separatorChar == '\\' 474: && path.length() > 1 && path.charAt (1) == ':' 475: && ((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') 476: || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))) 477: { 478: // On Windows, a process has a current working directory for 479: // each drive and a path like "G:foo\bar" would mean the 480: // absolute path "G:\wombat\foo\bar" if "\wombat" is the 481: // working directory on the G drive. 482: String drvDir = null; 483: try 484: { 485: drvDir = new File (path.substring (0, 2)).getCanonicalPath(); 486: } 487: catch (IOException e) 488: { 489: drvDir = path.substring (0, 2) + "\\"; 490: } 491: 492: // Note: this would return "C:\\." for the path "C:.", if "\" 493: // is the working folder on the C drive, but this is 494: // consistent with what Sun's JRE 1.4.1.01 actually returns! 495: if (path.length() > 2) 496: return drvDir + '\\' + path.substring (2, path.length()); 497: else 498: return drvDir; 499: } 500: else 501: return System.getProperty ("user.dir") + separatorChar + path; 502: } 503: 504: /** 505: * This method returns a <code>File</code> object representing the 506: * absolute path of this object. 507: * 508: * @return A <code>File</code> with the absolute path of the object. 509: * 510: * @since 1.2 511: */ 512: public File getAbsoluteFile() 513: { 514: return new File(getAbsolutePath()); 515: } 516: 517: /** 518: * This method returns a canonical representation of the pathname of 519: * this file. The actual form of the canonical representation is 520: * system-dependent. On the GNU system, conversion to canonical 521: * form involves the removal of redundant separators, references to 522: * "." and "..", and symbolic links. 523: * <p> 524: * Note that this method, unlike the other methods which return path 525: * names, can throw an IOException. This is because native method 526: * might be required in order to resolve the canonical path 527: * 528: * @exception IOException If an error occurs 529: */ 530: public native String getCanonicalPath() throws IOException; 531: 532: /** 533: * This method returns a <code>File</code> object representing the 534: * canonical path of this object. 535: * 536: * @return A <code>File</code> instance representing the canonical path of 537: * this object. 538: * 539: * @exception IOException If an error occurs. 540: * 541: * @since 1.2 542: */ 543: public File getCanonicalFile() throws IOException 544: { 545: return new File(getCanonicalPath()); 546: } 547: 548: /** 549: * This method returns the name of the file. This is everything in the 550: * complete path of the file after the last instance of the separator 551: * string. 552: * 553: * @return The file name 554: */ 555: public String getName() 556: { 557: int nameSeqIndex = 0; 558: 559: if (separatorChar == '\\' && path.length() > 1) 560: { 561: // On Windows, ignore the drive specifier or the leading '\\' 562: // of a UNC network path, if any (a.k.a. the "prefix"). 563: if ((path.charAt (0) == '\\' && path.charAt (1) == '\\') 564: || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') 565: || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')) 566: && path.charAt (1) == ':')) 567: { 568: if (path.length() > 2) 569: nameSeqIndex = 2; 570: else 571: return ""; 572: } 573: } 574: 575: String nameSeq 576: = (nameSeqIndex > 0 ? path.substring (nameSeqIndex) : path); 577: 578: int last = nameSeq.lastIndexOf (separatorChar); 579: 580: return nameSeq.substring (last + 1); 581: } 582: 583: /** 584: * This method returns a <code>String</code> the represents this file's 585: * parent. <code>null</code> is returned if the file has no parent. The 586: * parent is determined via a simple operation which removes the 587: * 588: * @return The parent directory of this file 589: */ 590: public String getParent() 591: { 592: String prefix = null; 593: int nameSeqIndex = 0; 594: 595: // The "prefix", if present, is the leading "/" on UNIX and 596: // either the drive specifier (e.g. "C:") or the leading "\\" 597: // of a UNC network path on Windows. 598: if (separatorChar == '/' && path.charAt (0) == '/') 599: { 600: prefix = "/"; 601: nameSeqIndex = 1; 602: } 603: else if (separatorChar == '\\' && path.length() > 1) 604: { 605: if ((path.charAt (0) == '\\' && path.charAt (1) == '\\') 606: || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') 607: || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')) 608: && path.charAt (1) == ':')) 609: { 610: prefix = path.substring (0, 2); 611: nameSeqIndex = 2; 612: } 613: } 614: 615: // According to the JDK docs, the returned parent path is the 616: // portion of the name sequence before the last separator 617: // character, if found, prefixed by the prefix, otherwise null. 618: if (nameSeqIndex < path.length()) 619: { 620: String nameSeq = path.substring (nameSeqIndex, path.length()); 621: int last = nameSeq.lastIndexOf (separatorChar); 622: if (last == -1) 623: return prefix; 624: else if (last == (nameSeq.length() - 1)) 625: // Note: The path would not have a trailing separator 626: // except for cases like "C:\" on Windows (see 627: // normalizePath( )), where Sun's JRE 1.4 returns null. 628: return null; 629: else if (last == 0) 630: last++; 631: 632: if (prefix != null) 633: return prefix + nameSeq.substring (0, last); 634: else 635: return nameSeq.substring (0, last); 636: } 637: else 638: // Sun's JRE 1.4 returns null if the prefix is the only 639: // component of the path - so "/" gives null on UNIX and 640: // "C:", "\\", etc. return null on Windows. 641: return null; 642: } 643: 644: /** 645: * This method returns a <code>File</code> object representing the parent 646: * file of this one. 647: * 648: * @return a <code>File</code> for the parent of this object. 649: * <code>null</code> 650: * will be returned if this object does not have a parent. 651: * 652: * @since 1.2 653: */ 654: public File getParentFile() 655: { 656: String parent = getParent(); 657: return parent != null ? new File(parent) : null; 658: } 659: 660: /** 661: * Returns the path name that represents this file. May be a relative 662: * or an absolute path name 663: * 664: * @return The pathname of this file 665: */ 666: public String getPath() 667: { 668: return path; 669: } 670: 671: /** 672: * This method returns a hash code representing this file. It is the 673: * hash code of the path of this file (as returned by <code>getPath()</code>) 674: * exclusived or-ed with the value 1234321. 675: * 676: * @return The hash code for this object 677: */ 678: public int hashCode() 679: { 680: if (caseSensitive) 681: return path.hashCode() ^ 1234321; 682: else 683: return path.toLowerCase().hashCode() ^ 1234321; 684: } 685: 686: /** 687: * This method returns true if this object represents an absolute file 688: * path and false if it does not. The definition of an absolute path varies 689: * by system. As an example, on GNU systems, a path is absolute if it starts 690: * with a "/". 691: * 692: * @return <code>true</code> if this object represents an absolute 693: * file name, <code>false</code> otherwise. 694: */ 695: public native boolean isAbsolute(); 696: 697: /* 698: * This method tests whether or not the file represented by this 699: * object is a directory. 700: */ 701: private boolean internalIsDirectory() 702: { 703: return _stat (DIRECTORY); 704: } 705: 706: /** 707: * This method tests whether or not the file represented by this object 708: * is a directory. In order for this method to return <code>true</code>, 709: * the file represented by this object must exist and be a directory. 710: * 711: * @return <code>true</code> if this file is a directory, <code>false</code> 712: * otherwise 713: * 714: * @exception SecurityException If reading of the file is not permitted 715: */ 716: public boolean isDirectory() 717: { 718: checkRead(); 719: return internalIsDirectory(); 720: } 721: 722: /** 723: * This method tests whether or not the file represented by this object 724: * is a "plain" file. A file is a plain file if and only if it 1) Exists, 725: * 2) Is not a directory or other type of special file. 726: * 727: * @return <code>true</code> if this is a plain file, <code>false</code> 728: * otherwise 729: * 730: * @exception SecurityException If reading of the file is not permitted 731: */ 732: public boolean isFile() 733: { 734: checkRead(); 735: return _stat (ISFILE); 736: } 737: 738: /** 739: * This method tests whether or not this file represents a "hidden" file. 740: * On GNU systems, a file is hidden if its name begins with a "." 741: * character. Files with these names are traditionally not shown with 742: * directory listing tools. 743: * 744: * @return <code>true</code> if the file is hidden, <code>false</code> 745: * otherwise. 746: * 747: * @since 1.2 748: */ 749: public boolean isHidden() 750: { 751: checkRead(); 752: return _stat (ISHIDDEN); 753: } 754: 755: /** 756: * This method returns the last modification time of this file. The 757: * time value returned is an abstract value that should not be interpreted 758: * as a specified time value. It is only useful for comparing to other 759: * such time values returned on the same system. In that case, the larger 760: * value indicates a more recent modification time. 761: * <p> 762: * If the file does not exist, then a value of 0 is returned. 763: * 764: * @return The last modification time of the file 765: * 766: * @exception SecurityException If reading of the file is not permitted 767: */ 768: public long lastModified() 769: { 770: checkRead(); 771: return attr (MODIFIED); 772: } 773: 774: /** 775: * This method returns the length of the file represented by this object, 776: * or 0 if the specified file does not exist. 777: * 778: * @return The length of the file 779: * 780: * @exception SecurityException If reading of the file is not permitted 781: */ 782: public long length() 783: { 784: checkRead(); 785: return attr (LENGTH); 786: } 787: 788: /* 789: * This native function actually produces the list of file in this 790: * directory 791: */ 792: private final native Object[] performList (FilenameFilter filter, 793: FileFilter fileFilter, 794: Class result_type); 795: 796: /** 797: * This method returns a array of <code>String</code>'s representing the 798: * list of files is then directory represented by this object. If this 799: * object represents a non-directory file or a non-existent file, then 800: * <code>null</code> is returned. The list of files will not contain 801: * any names such as "." or ".." which indicate the current or parent 802: * directory. Also, the names are not guaranteed to be sorted. 803: * <p> 804: * In this form of the <code>list()</code> method, a filter is specified 805: * that allows the caller to control which files are returned in the 806: * list. The <code>FilenameFilter</code> specified is called for each 807: * file returned to determine whether or not that file should be included 808: * in the list. 809: * <p> 810: * A <code>SecurityManager</code> check is made prior to reading the 811: * directory. If read access to the directory is denied, an exception 812: * will be thrown. 813: * 814: * @param filter An object which will identify files to exclude from 815: * the directory listing. 816: * 817: * @return An array of files in the directory, or <code>null</code> 818: * if this object does not represent a valid directory. 819: * 820: * @exception SecurityException If read access is not allowed to the 821: * directory by the <code>SecurityManager</code> 822: */ 823: public String[] list(FilenameFilter filter) 824: { 825: checkRead(); 826: return (String[]) performList (filter, null, String.class); 827: } 828: 829: /** 830: * This method returns a array of <code>String</code>'s representing the 831: * list of files is then directory represented by this object. If this 832: * object represents a non-directory file or a non-existent file, then 833: * <code>null</code> is returned. The list of files will not contain 834: * any names such as "." or ".." which indicate the current or parent 835: * directory. Also, the names are not guaranteed to be sorted. 836: * <p> 837: * A <code>SecurityManager</code> check is made prior to reading the 838: * directory. If read access to the directory is denied, an exception 839: * will be thrown. 840: * 841: * @return An array of files in the directory, or <code>null</code> if 842: * this object does not represent a valid directory. 843: * 844: * @exception SecurityException If read access is not allowed to the 845: * directory by the <code>SecurityManager</code> 846: */ 847: public String[] list() 848: { 849: checkRead(); 850: return (String[]) performList (null, null, String.class); 851: } 852: 853: /** 854: * This method returns an array of <code>File</code> objects representing 855: * all the files in the directory represented by this object. If this 856: * object does not represent a directory, <code>null</code> is returned. 857: * Each of the returned <code>File</code> object is constructed with this 858: * object as its parent. 859: * <p> 860: * A <code>SecurityManager</code> check is made prior to reading the 861: * directory. If read access to the directory is denied, an exception 862: * will be thrown. 863: * 864: * @return An array of <code>File</code> objects for this directory. 865: * 866: * @exception SecurityException If the <code>SecurityManager</code> denies 867: * access to this directory. 868: * 869: * @since 1.2 870: */ 871: public File[] listFiles() 872: { 873: checkRead(); 874: return (File[]) performList (null, null, File.class); 875: } 876: 877: /** 878: * This method returns an array of <code>File</code> objects representing 879: * all the files in the directory represented by this object. If this 880: * object does not represent a directory, <code>null</code> is returned. 881: * Each of the returned <code>File</code> object is constructed with this 882: * object as its parent. 883: * <p> 884: * In this form of the <code>listFiles()</code> method, a filter is specified 885: * that allows the caller to control which files are returned in the 886: * list. The <code>FilenameFilter</code> specified is called for each 887: * file returned to determine whether or not that file should be included 888: * in the list. 889: * <p> 890: * A <code>SecurityManager</code> check is made prior to reading the 891: * directory. If read access to the directory is denied, an exception 892: * will be thrown. 893: * 894: * @return An array of <code>File</code> objects for this directory. 895: * 896: * @exception SecurityException If the <code>SecurityManager</code> denies 897: * access to this directory. 898: * 899: * @since 1.2 900: */ 901: public File[] listFiles(FilenameFilter filter) 902: { 903: checkRead(); 904: return (File[]) performList (filter, null, File.class); 905: } 906: 907: /** 908: * This method returns an array of <code>File</code> objects representing 909: * all the files in the directory represented by this object. If this 910: * object does not represent a directory, <code>null</code> is returned. 911: * Each of the returned <code>File</code> object is constructed with this 912: * object as its parent. 913: * <p> 914: * In this form of the <code>listFiles()</code> method, a filter is specified 915: * that allows the caller to control which files are returned in the 916: * list. The <code>FileFilter</code> specified is called for each 917: * file returned to determine whether or not that file should be included 918: * in the list. 919: * <p> 920: * A <code>SecurityManager</code> check is made prior to reading the 921: * directory. If read access to the directory is denied, an exception 922: * will be thrown. 923: * 924: * @return An array of <code>File</code> objects for this directory. 925: * 926: * @exception SecurityException If the <code>SecurityManager</code> denies 927: * access to this directory. 928: * 929: * @since 1.2 930: */ 931: public File[] listFiles(FileFilter filter) 932: { 933: checkRead(); 934: return (File[]) performList (null, filter, File.class); 935: } 936: 937: /** 938: * This method returns a <code>String</code> that is the path name of the 939: * file as returned by <code>getPath</code>. 940: * 941: * @return A <code>String</code> representation of this file 942: */ 943: public String toString() 944: { 945: return path; 946: } 947: 948: /** 949: * @return A <code>URI</code> for this object. 950: */ 951: public URI toURI() 952: { 953: String abspath = getAbsolutePath(); 954: 955: if (isDirectory()) 956: abspath = abspath + separator; 957: 958: try 959: { 960: return new URI("file", abspath.replace(separatorChar, '/'), null); 961: } 962: catch (URISyntaxException use) 963: { 964: // Can't happen. 965: throw new RuntimeException(use); 966: } 967: } 968: 969: /** 970: * This method returns a <code>URL</code> with the <code>file:</code> 971: * protocol that represents this file. The exact form of this URL is 972: * system dependent. 973: * 974: * @return A <code>URL</code> for this object. 975: * 976: * @exception MalformedURLException If the URL cannot be created 977: * successfully. 978: */ 979: public URL toURL() throws MalformedURLException 980: { 981: // On Win32, Sun's JDK returns URLs of the form "file:/c:/foo/bar.txt", 982: // while on UNIX, it returns URLs of the form "file:/foo/bar.txt". 983: if (separatorChar == '\\') 984: return new URL ("file:/" + getAbsolutePath().replace ('\\', '/') 985: + (isDirectory() ? "/" : "")); 986: else 987: return new URL ("file:" + getAbsolutePath() 988: + (isDirectory() ? "/" : "")); 989: } 990: 991: /* 992: * This native method actually creates the directory 993: */ 994: private final native boolean performMkdir(); 995: 996: /** 997: * This method creates a directory for the path represented by this object. 998: * 999: * @return <code>true</code> if the directory was created, 1000: * <code>false</code> otherwise 1001: * 1002: * @exception SecurityException If write access is not allowed to this file 1003: */ 1004: public boolean mkdir() 1005: { 1006: checkWrite(); 1007: return performMkdir(); 1008: } 1009: 1010: private static boolean mkdirs (File x) 1011: { 1012: if (x.isDirectory()) 1013: return true; 1014: String p = x.getPath(); 1015: String parent = x.getParent(); 1016: if (parent != null) 1017: { 1018: x.path = parent; 1019: if (! mkdirs (x)) 1020: return false; 1021: x.path = p; 1022: } 1023: return x.mkdir(); 1024: } 1025: 1026: /** 1027: * This method creates a directory for the path represented by this file. 1028: * It will also create any intervening parent directories if necessary. 1029: * 1030: * @return <code>true</code> if the directory was created, 1031: * <code>false</code> otherwise 1032: * 1033: * @exception SecurityException If write access is not allowed to this file 1034: */ 1035: public boolean mkdirs() 1036: { 1037: checkWrite(); 1038: if (isDirectory()) 1039: return false; 1040: return mkdirs (new File (path)); 1041: } 1042: 1043: private static synchronized String nextValue() 1044: { 1045: return Long.toString(counter++, Character.MAX_RADIX); 1046: } 1047: 1048: /** 1049: * This method creates a temporary file in the specified directory. If 1050: * the directory name is null, then this method uses the system temporary 1051: * directory. The files created are guaranteed not to currently exist and 1052: * the same file name will never be used twice in the same virtual 1053: * machine instance. 1054: * The system temporary directory is determined by examinging the 1055: * <code>java.io.tmpdir</code> system property. 1056: * <p> 1057: * The <code>prefix</code> parameter is a sequence of at least three 1058: * characters that are used as the start of the generated filename. The 1059: * <code>suffix</code> parameter is a sequence of characters that is used 1060: * to terminate the file name. This parameter may be <code>null</code> 1061: * and if it is, the suffix defaults to ".tmp". 1062: * <p> 1063: * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code> 1064: * method is used to verify that this operation is permitted. 1065: * 1066: * @param prefix The character prefix to use in generating the path name. 1067: * @param suffix The character suffix to use in generating the path name. 1068: * @param directory The directory to create the file in, or 1069: * <code>null</code> for the default temporary directory 1070: * 1071: * @exception IllegalArgumentException If the patterns is not valid 1072: * @exception SecurityException If there is no permission to perform 1073: * this operation 1074: * @exception IOException If an error occurs 1075: * 1076: * @since 1.2 1077: */ 1078: public static File createTempFile(String prefix, String suffix, 1079: File directory) 1080: throws IOException 1081: { 1082: // Grab the system temp directory if necessary 1083: if (directory == null) 1084: { 1085: String dirname = tmpdir; 1086: if (dirname == null) 1087: throw new IOException("Cannot determine system temporary directory"); 1088: 1089: directory = new File(dirname); 1090: if (!directory.internalExists()) 1091: throw new IOException("System temporary directory " 1092: + directory.getName() + " does not exist."); 1093: if (!directory.internalIsDirectory()) 1094: throw new IOException("System temporary directory " 1095: + directory.getName() 1096: + " is not really a directory."); 1097: } 1098: 1099: // Check if prefix is at least 3 characters long 1100: if (prefix.length() < 3) 1101: throw new IllegalArgumentException("Prefix too short: " + prefix); 1102: 1103: // Set default value of suffix 1104: if (suffix == null) 1105: suffix = ".tmp"; 1106: 1107: // Truncation rules. 1108: // `6' is the number of characters we generate. 1109: if (prefix.length() + 6 + suffix.length() > maxPathLen) 1110: { 1111: int suf_len = 0; 1112: if (suffix.charAt(0) == '.') 1113: suf_len = 4; 1114: suffix = suffix.substring(0, suf_len); 1115: if (prefix.length() + 6 + suf_len > maxPathLen) 1116: prefix = prefix.substring(0, maxPathLen - 6 - suf_len); 1117: } 1118: 1119: File f; 1120: 1121: // How many times should we try? We choose 100. 1122: for (int i = 0; i < 100; ++i) 1123: { 1124: // This is ugly. 1125: String t = "ZZZZZZ" + nextValue(); 1126: String l = prefix + t.substring(t.length() - 6) + suffix; 1127: try 1128: { 1129: f = new File(directory, l); 1130: if (f.createNewFile()) 1131: return f; 1132: } 1133: catch (IOException ignored) 1134: { 1135: } 1136: } 1137: 1138: throw new IOException ("cannot create temporary file"); 1139: } 1140: 1141: /* 1142: * This native method sets the permissions to make the file read only. 1143: */ 1144: private native boolean performSetReadOnly(); 1145: 1146: /** 1147: * This method sets the file represented by this object to be read only. 1148: * A read only file or directory cannot be modified. Please note that 1149: * GNU systems allow read only files to be deleted if the directory it 1150: * is contained in is writable. 1151: * 1152: * @return <code>true</code> if the operation succeeded, <code>false</code> 1153: * otherwise. 1154: * 1155: * @exception SecurityException If the <code>SecurityManager</code> does 1156: * not allow this operation. 1157: * 1158: * @since 1.2 1159: */ 1160: public boolean setReadOnly() 1161: { 1162: // Do a security check before trying to do anything else. 1163: checkWrite(); 1164: return performSetReadOnly(); 1165: } 1166: 1167: private static native File[] performListRoots(); 1168: 1169: /** 1170: * This method returns an array of filesystem roots. Some operating systems 1171: * have volume oriented filesystem. This method provides a mechanism for 1172: * determining which volumes exist. GNU systems use a single hierarchical 1173: * filesystem, so will have only one "/" filesystem root. 1174: * 1175: * @return An array of <code>File</code> objects for each filesystem root 1176: * available. 1177: * 1178: * @since 1.2 1179: */ 1180: public static File[] listRoots() 1181: { 1182: File[] roots = performListRoots(); 1183: 1184: SecurityManager s = System.getSecurityManager(); 1185: if (s != null) 1186: { 1187: // Only return roots to which the security manager permits read access. 1188: int count = roots.length; 1189: for (int i = 0; i < roots.length; i++) 1190: { 1191: try 1192: { 1193: s.checkRead (roots[i].path); 1194: } 1195: catch (SecurityException sx) 1196: { 1197: roots[i] = null; 1198: count--; 1199: } 1200: } 1201: if (count != roots.length) 1202: { 1203: File[] newRoots = new File[count]; 1204: int k = 0; 1205: for (int i=0; i < roots.length; i++) 1206: { 1207: if (roots[i] != null) 1208: newRoots[k++] = roots[i]; 1209: } 1210: roots = newRoots; 1211: } 1212: } 1213: return roots; 1214: } 1215: 1216: /** 1217: * This method creates a temporary file in the system temporary directory. 1218: * The files created are guaranteed not to currently exist and the same file 1219: * name will never be used twice in the same virtual machine instance. The 1220: * system temporary directory is determined by examinging the 1221: * <code>java.io.tmpdir</code> system property. 1222: * <p> 1223: * The <code>prefix</code> parameter is a sequence of at least three 1224: * characters that are used as the start of the generated filename. The 1225: * <code>suffix</code> parameter is a sequence of characters that is used 1226: * to terminate the file name. This parameter may be <code>null</code> 1227: * and if it is, the suffix defaults to ".tmp". 1228: * <p> 1229: * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code> 1230: * method is used to verify that this operation is permitted. 1231: * <p> 1232: * This method is identical to calling 1233: * <code>createTempFile(prefix, suffix, null)</code>. 1234: * 1235: * @param prefix The character prefix to use in generating the path name. 1236: * @param suffix The character suffix to use in generating the path name. 1237: * 1238: * @exception IllegalArgumentException If the prefix or suffix are not valid. 1239: * @exception SecurityException If there is no permission to perform 1240: * this operation 1241: * @exception IOException If an error occurs 1242: */ 1243: public static File createTempFile(String prefix, String suffix) 1244: throws IOException 1245: { 1246: return createTempFile(prefix, suffix, null); 1247: } 1248: 1249: /** 1250: * This method compares the specified <code>File</code> to this one 1251: * to test for equality. It does this by comparing the canonical path names 1252: * of the files. 1253: * <p> 1254: * The canonical paths of the files are determined by calling the 1255: * <code>getCanonicalPath</code> method on each object. 1256: * <p> 1257: * This method returns a 0 if the specified <code>Object</code> is equal 1258: * to this one, a negative value if it is less than this one 1259: * a positive value if it is greater than this one. 1260: * 1261: * @return An integer as described above 1262: * 1263: * @since 1.2 1264: */ 1265: public int compareTo(File other) 1266: { 1267: if (caseSensitive) 1268: return path.compareTo (other.path); 1269: else 1270: return path.compareToIgnoreCase (other.path); 1271: } 1272: 1273: /** 1274: * This method compares the specified <code>Object</code> to this one 1275: * to test for equality. It does this by comparing the canonical path names 1276: * of the files. This method is identical to <code>compareTo(File)</code> 1277: * except that if the <code>Object</code> passed to it is not a 1278: * <code>File</code>, it throws a <code>ClassCastException</code> 1279: * <p> 1280: * The canonical paths of the files are determined by calling the 1281: * <code>getCanonicalPath</code> method on each object. 1282: * <p> 1283: * This method returns a 0 if the specified <code>Object</code> is equal 1284: * to this one, a negative value if it is less than this one 1285: * a positive value if it is greater than this one. 1286: * 1287: * @return An integer as described above 1288: * 1289: * @exception ClassCastException If the passed <code>Object</code> is 1290: * not a <code>File</code> 1291: * 1292: * @since 1.2 1293: */ 1294: public int compareTo(Object obj) 1295: { 1296: return compareTo((File) obj); 1297: } 1298: 1299: /* 1300: * This native method actually performs the rename. 1301: */ 1302: private native boolean performRenameTo (File dest); 1303: 1304: /** 1305: * This method renames the file represented by this object to the path 1306: * of the file represented by the argument <code>File</code>. 1307: * 1308: * @param dest The <code>File</code> object representing the target name 1309: * 1310: * @return <code>true</code> if the rename succeeds, <code>false</code> 1311: * otherwise. 1312: * 1313: * @exception SecurityException If write access is not allowed to the 1314: * file by the <code>SecurityMananger</code>. 1315: */ 1316: public synchronized boolean renameTo(File dest) 1317: { 1318: SecurityManager s = System.getSecurityManager(); 1319: if (s != null) 1320: { 1321: s.checkWrite (getPath()); 1322: s.checkWrite (dest.getPath()); 1323: } 1324: return performRenameTo (dest); 1325: } 1326: 1327: /* 1328: * This method does the actual setting of the modification time. 1329: */ 1330: private native boolean performSetLastModified(long time); 1331: 1332: /** 1333: * This method sets the modification time on the file to the specified 1334: * value. This is specified as the number of seconds since midnight 1335: * on January 1, 1970 GMT. 1336: * 1337: * @param time The desired modification time. 1338: * 1339: * @return <code>true</code> if the operation succeeded, <code>false</code> 1340: * otherwise. 1341: * 1342: * @exception IllegalArgumentException If the specified time is negative. 1343: * @exception SecurityException If the <code>SecurityManager</code> will 1344: * not allow this operation. 1345: * 1346: * @since 1.2 1347: */ 1348: public boolean setLastModified(long time) 1349: { 1350: if (time < 0) 1351: throw new IllegalArgumentException("Negative modification time: " + time); 1352: 1353: checkWrite(); 1354: return performSetLastModified(time); 1355: } 1356: 1357: private void checkWrite() 1358: { 1359: // Check the SecurityManager 1360: SecurityManager s = System.getSecurityManager(); 1361: 1362: if (s != null) 1363: s.checkWrite(path); 1364: } 1365: 1366: private void checkRead() 1367: { 1368: // Check the SecurityManager 1369: SecurityManager s = System.getSecurityManager(); 1370: 1371: if (s != null) 1372: s.checkRead(path); 1373: } 1374: 1375: /** 1376: * Calling this method requests that the file represented by this object 1377: * be deleted when the virtual machine exits. Note that this request cannot 1378: * be cancelled. Also, it will only be carried out if the virtual machine 1379: * exits normally. 1380: * 1381: * @exception SecurityException If deleting of the file is not allowed 1382: * 1383: * @since 1.2 1384: */ 1385: // FIXME: This should use the ShutdownHook API once we implement that. 1386: public void deleteOnExit() 1387: { 1388: // Check the SecurityManager 1389: SecurityManager sm = System.getSecurityManager(); 1390: if (sm != null) 1391: sm.checkDelete (getPath()); 1392: 1393: DeleteFileHelper.add(this); 1394: } 1395: 1396: private void writeObject(ObjectOutputStream oos) throws IOException 1397: { 1398: oos.defaultWriteObject(); 1399: oos.writeChar(separatorChar); 1400: } 1401: 1402: private void readObject(ObjectInputStream ois) 1403: throws ClassNotFoundException, IOException 1404: { 1405: ois.defaultReadObject(); 1406: 1407: // If the file was from an OS with a different dir separator, 1408: // fixup the path to use the separator on this OS. 1409: char oldSeparatorChar = ois.readChar(); 1410: 1411: if (oldSeparatorChar != separatorChar) 1412: path = path.replace(oldSeparatorChar, separatorChar); 1413: } 1414: 1415: } // class File