Sharkysoft home

lava.io
Class Path

java.lang.Object
  |
  +--lava.io.Path
All Implemented Interfaces:
java.lang.Comparable

public class Path
extends java.lang.Object
implements java.lang.Comparable

File in virtual/physical Unix file system.

Details: Path is a replacement for java.io.File, the class that Sun screwed up. Unlike File, this class takes a hard stand on what paths should look like and how they are handled. This allows you, the developer, to engage in worry-free path manipulation without fear of platform-dependent gotchas. Path also reduces the developer's dependecy on java.io.File, which has always been plagued with quirky behavior.

platform independence

Path's most significant feature is that it provides a uniform, hassle-free interface for manipulating file paths. This is achieved by defining the path syntax to work in a manner that does not require the developer be overly concerned with platform-independence. (I guess I already said this, didn't I?) When using Path, for example, the developer can always assume that the path separator is "/", regardless of the platform, thereby liberating the programmer from the need to make silly calls such as System.getProperty ("file.separator") just to figure out how to build a path name. Path detects the host system's needs and translates the paths for you when platform-dependent representations are needed.

path equivalence

Unlike File, Path correctly detects when two file specifications are equivalent. This makes it easy to detect duplicate files when large lists of files are being processed.

All path specifications are automatically reduced to their simplest form before they are interpreted or used by any other method. For example, the path "bob/../anne/index.html" is automatically reduced to "anne/index.html" before it is processed, and to Path instances created with either path in the constructor would be equivalent to each other.

Also, the parent of the root directory is the root directory. Thus, the paths "/", "/..", and "/../.." are all equivalent.

platform mapping

Path uses the UNIX style path naming conventions for all platforms. Paths can be constructed from File objects. When this happens, Path attempts to preserve the relativeness or absoluteness of the file being represented.

Because Path attempts to make paths on all file systems look like UNIX paths, the path names for non-Unix platforms such as Windows and Macintosh have to be "unixized." This is achieved as follows:

Windows

Path presents a virtual file system that has the feel of a Unix file system but encapsulates all of the features of Window-specific paths.

Since Path is pure Java, Path internally uses java.io.File for many of its operations. This often requires the creation of a File object from a Path object. In many instances, the conversion may be impossible. For example, there is no straightforward way to convert the path "/etc/passwd" into a Windows File, since this path does not include a representation of a drive letter. On Windows platforms, Path automatically treats non-drive-specifying absolute paths as absolute paths on the current working drive. Care should be taken when using this feature if the current working drive is subject to change within your Windows-Java application.

case sensitivity

Unix is case-sensitive; Windows is not. Therefore, to allow the Windows file system to behave more like a Unix file system, paths matching filenames whose cases are different are considered to be distinct. For example, if the Window file C:\AUTOEXEC.BAT exists, then the virtual Unix file /C/AUTOEXEC.BAT exists, but /C/autoexec.bat does not.

Macintosh

Path does not yet support Macintosh platforms due to lack of information about Macintosh pathname formats and how they are interpreted by the java.io.File object. Help would be appreciated.

Version:
2000.11.11
Author:
Sharky

Field Summary
static int CHANGE_ROOT
          Forces root dir on relative path.
static int CONDITIONAL_RELATIVE
          Resolve relative path.
static int FORCE_RELATIVE
          Concatenates two paths.
 
Constructor Summary
Path(Path base, Path rel, int mode)
          Combines two path components.
Path(Path base, java.lang.String rel, int mode)
          Combines two path components.
Path(java.lang.String pathname)
          Initializes with relative or absolute path.
Path(java.lang.String base, java.lang.String rel, int mode)
          Combines two path components.
 
Method Summary
 Path adjustCase()
          Corrects case to match existing files.
 int compareTo(java.lang.Object o2)
           
 void createAsDirectory(boolean mkdir)
          Creates file.
 void createAsFile(boolean mkdir)
          Creates file.
static Path createFromJavaFile(java.io.File file)
          Converts File to Path.
 boolean equals(java.lang.Object o)
          Tests for equivalence.
 boolean exists()
          Tests existance.
 Path getCanonicalPath()
           
 java.lang.String getFileName()
           
 long getLastModifiedTime()
          Returns modification timestamp.
 Path getParentDirectory()
           
static Path getRootDirectory()
          Returns root directory.
 long getSize()
          Returns file size.
static Path getWorkingDirectory()
          Returns working directory.
 int hashCode()
          Returns hash code.
 boolean isAbsolute()
          Tells whether path is absolute.
 boolean isDataFile()
          Determines whether path is file.
 boolean isDirectory()
          Determines whether path is directory.
 boolean isReadable()
          Determines whether file is readable.
 boolean isRelative()
           
 boolean isWritable()
          Determines whether file is writable.
 Path[] list()
          Lists directory contents.
 void move(Path dest)
          Moves file.
 void setLastModifiedTime(long new_time)
           
 Path toAbsolutePath()
          Converts to absolute path.
 java.io.File toJavaFile()
           
 Path toRelativePath()
          Converts to relative path.
 Path toRelativePath(Path wd)
          Converts to relative path.
 java.lang.String toString()
          Returns path.
 void unlink()
          Deletes file or directory.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

CONDITIONAL_RELATIVE

public static final int CONDITIONAL_RELATIVE
Resolve relative path.

Details: CONDITIONAL_RELATIVE indicates that the constructor should attempt to determine an path based on the given working directory (base) and the given relative path (rel). If rel is an absolute path name (i.e., begins with '/'), then the working directory is ignored. If both base and rel are relative, the resulting Path will also be relative.

This construction mode differs from FORCE_RELATIVE in that the resulting path will only be formed from both strings if rel is a relative path.


FORCE_RELATIVE

public static final int FORCE_RELATIVE
Concatenates two paths.

Details: FORCE_RELATIVE indicates that the path should be formed by concatenating the two paths (base, rel), regardless of whether either is absolute or relative. The result will be relative only if base is relative.

Regardless of whether base ends with a slash or rel begins with a slash, or both, or neither, the constructor will make sure that exactly one slash appears between both components.


CHANGE_ROOT

public static final int CHANGE_ROOT
Forces root dir on relative path.

Details: CHANGE_ROOT indicates that the path should be formed by treating rel as an absolute path, but with its root at base. In particular, this means that even if rel contains many ".." components, the path will be shallower than base.

Since:
2000.11.11
Constructor Detail

Path

public Path(java.lang.String pathname)
Initializes with relative or absolute path.

Details: This constructor initializes a new Path by setting the path equal to pathname.

Parameters:
pathname - the path name

Path

public Path(java.lang.String base,
            java.lang.String rel,
            int mode)
Combines two path components.

Details: This constructor initializes a new Path based on two given path elements (base, rel). The manner in which these elements are combined is determined by the given combination mode (mode). Valid modes are CONDITIONAL_RELATIVE and FORCE_RELATIVE. See the documentation for those identifiers for more information.

Parameters:
base - the base component
rel - the relative component
See Also:
CONDITIONAL_RELATIVE, FORCE_RELATIVE, CHANGE_ROOT

Path

public Path(Path base,
            java.lang.String rel,
            int mode)
Combines two path components.

Details: This constructor does the same thing as Path(String,String), except that the first parameter is given as an already constructed Path.


Path

public Path(Path base,
            Path rel,
            int mode)
Combines two path components.

Details: This constructor does the same thing as Path(String,String), except that the first two parameters are given as already constructed Paths.

Method Detail

getWorkingDirectory

public static Path getWorkingDirectory()
Returns working directory.

Details: getWorkingDirectory creates a new Path instance based on the VM's current working directory and returns it as an absolute path.

Returns:
the current directory

createFromJavaFile

public static final Path createFromJavaFile(java.io.File file)
Converts File to Path.

Details: createFromJavaFile converts instances of java.io.File into Paths, recognizing the file system requirements of the host VM's platform. If the current platform is not Unix, the path will be unixized as described in the class notes.

Parameters:
file - the File
Returns:
the Path

toJavaFile

public java.io.File toJavaFile()

getRootDirectory

public static Path getRootDirectory()
Returns root directory.

Details: getRootDirectory returns a Path representing the root directory.

Returns:
the root directory

isAbsolute

public final boolean isAbsolute()
Tells whether path is absolute.

Details: isAbsolute returns true if this path is absolute, false otherwise. A path is absolute if and only if its name begins with a slash ('/').

Returns:
true iff path is absolute

getParentDirectory

public Path getParentDirectory()

getFileName

public java.lang.String getFileName()

toAbsolutePath

public Path toAbsolutePath()
Converts to absolute path.

Details: toAbsolutePath creates a new, absolute path based on this path and returns it. This path is resolved using the current working directory.

Returns:
the absolute path

toRelativePath

public Path toRelativePath(Path wd)
Converts to relative path.

Details: If this Path is relative, toRelativePath simply returns this. Otherwise, toRelativePath determines the shortest relative Path which, when resolved from wd, indicates the same Path as this Path

Parameters:
wd - the "working" directory
Returns:
the relative Path

toRelativePath

public Path toRelativePath()
Converts to relative path.

Details: This method is the same as toRelativePath(Path), except that the VM's current working directory is supplied as the first parameter.


isRelative

public boolean isRelative()

getCanonicalPath

public Path getCanonicalPath()
                      throws java.io.IOException

exists

public boolean exists()
               throws java.io.IOException
Tests existance.

Details: exists returns true if the file targeted by this path exists, false otherwise. If this path is relative, it is first resolved using the current working directory.

If exists cannot convert this path into system-dependent File object, this method automatically returns false. Note that this means in Windows, paths that don't begin with "/X", where X is a drive letter, never exist.

Windows notes: Note that in Java, there is no way (short of native methods) to detect whether a given computer exists on the network. Thus, paths of the form "/NET/SERVERNAME" are considered by exists to always exist. Similarly, there is no way to determine whether network browsing is enabled. Therefore, exists simply returns a default value of true if this path is "/NET". Of course, exists also returns true for "/".

Returns:
true if the file exists

isDirectory

public boolean isDirectory()
                    throws java.io.IOException
Determines whether path is directory.

Details: isDirectory determines whether the file targeted by this path can be treated as a directory. (In Unix-speak, this means that soft links to directories are OK.) If it can, then isDirectory returns true. If it can not be, or if the file doesn't exist, isDirectory returns false.

If a platform-specific File representation of this Path cannot be created, this method automatically returns false (with one exception for Windows). Otherwise, this method returns the result of calling isDirectory on the equivalent File object.

Returns:
true if path targets an existing directory

isDataFile

public boolean isDataFile()
                   throws java.io.IOException
Determines whether path is file.

Details: isDataFile determines whether the file targeted by this path can be treated as a normal data file. If it can, then isDataFile returns true. If it can not be, or if the file doesn't exist, then isDataFile returns false.

If a platform-specific File representation of this Path cannot be created, this method returns false. Otherwise, this method returns the result of calling isFile on the equivalent File object.

Returns:
true if path targets an existing data file

isReadable

public boolean isReadable()
                   throws java.io.IOException
Determines whether file is readable.

Details: First, isReadable returns false if exists would return false. Otherwise, isReadable determines whether the file is a directory or a data file. If the file is a directory, isReadable returns true if and only if the directory's contents can be read. If the file is a data file, isReadable returns true if and only if the file's contents can be read.

This method is similar to java.io.File.canRead, except that this implementation actually works. Note, in particular, that the Windows version of File.canRead does not always tell the truth. This implementation, however, does not lie, since in Windows it performs an actual read test on the file.

The Unix implementation also provides full functionality but does not require a test-read, since permissions in the meta-data provide the necessary clues to determine readability.

Returns:
true if the file or directory is readable

isWritable

public boolean isWritable()
                   throws java.io.IOException
Determines whether file is writable.

Details: First, isWritable returns false if exists would return false. Otherwise, isWritable determines whether the file is a directory or a data file. If the file is a directory, isWritable returns true if and only if the directory can be deleted (assuming it is empty). If the file is a data file, isWritable returns true if and only if the file's contents can be updated.

This method is similar to java.io.File.canWrite, except that its specification is more clear.

Unix notes: In Unix, if a directory is not writable then not only can it not be deleted, but files inside it cannot be deleted or created either. Already existing files in the directory can still be updated, however.

Windows notes: In Windows, directories marked as "read only" usually resist being deleted, but do not necessarily resist attempts to create new files or delete existing files within them. There may be exceptions in the case of shared directories or mapped network drives, however. In Windows, it may not be possible to determine whether a directory's file table is truly read only without actually attempting to create or delete a file. If a directory shared by a Samba server appears to not be writable, as indicated by this method, then it is probably the case that the file table is not writable as well.

Returns:
true if the file or directory is readable

getSize

public long getSize()
             throws java.io.IOException
Returns file size.

Details: getSize returns the size of this file, if it exists, or throws a FileNotFoundException if it does not. If this is a directory, getSize returns -1.

This method is similar to java.io.File.length, except that its behavior is consistent across platforms with respect to the sizes reported for directories. In Unix, for example, length returns the size of the directory's inode table, but in Windows, length returns 0 regardless of the file table size. This is inconsistent behavior that detracts from the portability of Java applications.

This method takes a stand on what ought to be returned and returns it.

Returns:
the size of the file
Throws:
java.io.FileNotFoundException - if the file does not exist

getLastModifiedTime

public long getLastModifiedTime()
                         throws java.io.IOException
Returns modification timestamp.

Details: getLastModifiedTime returns the time, in milliseconds since the 1970 epoch, that this file was last modified. If this file is a directory and the platform is Unix, the last modified time indicates the time of last modification to the directory's inode structure. In Windows, the last modified time usually refers to the time the directory was created.

getLastModifiedTime throws a FileNotFoundException if the file does not exist.

Returns:
the modification timestamp
Throws:
java.io.FileNotFoundException - if the file does not exist

list

public Path[] list()
            throws java.io.IOException
Lists directory contents.

Details: list treats this path as a directory and attempts to list its contents. If this path does not exist or is not a directory, or if it is a diretory but is not readable, list throws an IOException. Otherwise, the contents of this diretory are returned in an array of Paths. If this path is relative, it is first resolved using the current working directory. In either case, each element in the returned array is automatically represented as an absolute path, since each element refers to an actually existing file.

Windows notes: If this path is "/", list returns a drive list, in the form of {"/A", "/C", "/D", ...}. Included in this list is also the Network Neighborhood virtual directory, "/NET". If this path is "/NET" or "/NET/servername", however, list returns an empty list, since browsing is not possible in pure Java code. (Actually, it is possible, but Sharky is not willing to implement an SMB client in Java. Sorry. Any volunteers?)

Returns:
the directory contents

createAsFile

public void createAsFile(boolean mkdir)
                  throws java.io.IOException
Creates file.

Details: createAsFile attempts to create a zero-length file whose location is identified by this path. If the file cannot be created, createAsFile throws an IOException. Possible reasons for failure include:

If mkdir is true, any necessary parent directories will automatically be created.

createAsFile throws an IOException if the file cannot be created.

Parameters:
mkdir - whether or not parent directories should be created
Throws:
java.io.IOException - if the directory cannot be created

createAsDirectory

public void createAsDirectory(boolean mkdir)
                       throws java.io.IOException
Creates file.

Details: createAsDirectory attempts to create a directory whose location is identified by this path. If the directory cannot be created, createAsDirectory throws an IOException. Possible reasons for failure include:

If mkdir is true, any necessary parent directories will automatically be created.

createAsDirectory throws an IOException if the directory cannot be created.

Parameters:
mkdir - whether or not parent directories should be created
Throws:
java.io.IOException - if the file cannot be created

unlink

public void unlink()
            throws java.io.IOException
Deletes file or directory.

Details: unlink removes the directory or file represented by this path. If this path is a directory, then the directory must be empty for the unlink operation to succeed. If unlink fails, an IOException is thrown.

Throws:
java.io.IOException - if the file or directory cannot be deleted

setLastModifiedTime

public void setLastModifiedTime(long new_time)
                         throws java.io.IOException

move

public void move(Path dest)
          throws java.io.IOException
Moves file.

Details: move moves this file or directory to the target file or directory. If the target is an existing directory, this file will be placed in that directory under its same name. Otherwise, move will attempt to move and/or rename this file or directory so that it has the same path as dest. In short, this method behaves like the Unix mv command.

If the target (dest) exists and is not a directory, the file already at dest will be overwritten by this file. If the operation fails, an IOException will be thrown.

Parameters:
dest - the target
Throws:
java.io.IOException - if the operation cannot complete

equals

public boolean equals(java.lang.Object o)
Tests for equivalence.

Details: equals fulfills its contract as described in java.lang.Object. Here are the relevant implementation details:

  1. If o is null or is not a Path, return false.
  2. If o is relative but this is absolute, or vice-versa, return false.
  3. Otherwise, return true if the paths match.
Overrides:
equals in class java.lang.Object
Parameters:
o - the object to compare
Returns:
true iff o represents the same path as this

hashCode

public int hashCode()
Returns hash code.

Details: hashCode fulfills its contract as described in java.lang.Object.

Overrides:
hashCode in class java.lang.Object

toString

public java.lang.String toString()
Returns path.

Details: toString returns a string representation of this Path. This may not be the same value provided at construction time, but it will be equivalent.

Overrides:
toString in class java.lang.Object
Returns:
the path

compareTo

public int compareTo(java.lang.Object o2)
Specified by:
compareTo in interface java.lang.Comparable

adjustCase

public Path adjustCase()
Corrects case to match existing files.

Details: On non-Windows platforms, adjustCase simply returns this. On Windows, adjust case corrects the case of characters in the filename to match the case of actual directory and file names found on the hard drive. Because Path is case-sensitive, adjustCase must be used to convert nearly-matching Paths into matching paths if case-sensitive behavior is not desired.

Returns:
adjusted Path
Since:
2001.03.09

Sharkysoft home