Source for java.io.File

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