The File Class

Instances of the java.io.File class represent filenames on the local system, not actual files. Occasionally, this distinction is crucial. For instance, File objects can represent directories as well as files. Also, you cannot assume that a file exists just because you have a File object for a file.

public class File extends Object implements Serializable, Comparable

Although there are no guarantees that a file named by a File object actually exists, the File class does contain many methods for getting information about the attributes of a file and for manipulating those files. The File class attempts to account for system-dependent features like the file separator character and file attributes.

Each File object contains a single String field called path that contains either a relative or absolute path to the file, including the name of the file or directory itself:

private String path

Many methods in this class work solely by looking at this string. They do not necessarily look at any part of the filesystem.

17.3.1. Constructing File Objects

The java.io.File class has three constructors. Each accepts some variation of a filename as an argument. This one is the simplest:

public File(String path)

The path argument should be either an absolute or relative path to the file in a format understood by the host operating system. For example, using Unix filename conventions:

File uf1 = new File("25.html"); File uf2 = new File("course/week2/25.html"); File uf3 = new File("/public/html/course/week2/25.html");

Much poorly written Java code implicitly assumes Unix filename conventions, and most VMs take this into account. Therefore, code that assumes Unix conventions is likely to produce reasonable results on most operating systems. Windows VMs generally allow you to use Windows conventions instead. For example:

File wf1 = new File("25.htm"); File wf2 = new File("course\week2\25.html"); File wf3 = new File("D:\public\html\course\week2\25.htm");

The double backslashes are merely the escape sequence for the single backslash in a string literal. Otherwise, attempts to compile this code would generate an "Invalid escape character" error message. Remember that is a tab, a linefeed, and so on. Here, however, we need a backslash to simply be a backslash.

The second File constructor specifies an absolute or relative pathname and a filename:

public File(String directory, String filename)

For example:

File f2 = new File("course/week2", "25.html");

This produces a File object with the path field set to course/week2/25.html. The constructor is smart enough to handle the case of directories with and without trailing separators. The third constructor is identical to the second, except that the first argument is a File object instead of a string.

public File(File directory, String filename)

This third constructor is the most robust of the lot, provided the filename is only a filename like readme.txt and not a relative path like cryptozip/readme.txt. The reason is that this constructor guarantees the use of the local path separator character and is thus more platform-independent. You can use this to build a file structure that works on all platforms regardless of path separators or normalization routines. For example, suppose you want to build a File object that points to the file com/elharo/io/StreamCopier.class. The following four lines do this without reference to the file separator character:

File temp = new File("com"); temp = new File(temp, "elharo"); temp = new File(temp, "io"); File scfile = new File(temp, "StreamCopier.class");

None of these constructors throw any exceptions. All the constructor does is set the path field; Java never checks to see whether the file named by path actually exists or even whether the name passed to the constructor is a valid filename. For example, the following File object causes problems on Unix, OS/2, Mac OS 9, Mac OS X, and Windows, but you can still construct it:

File f = new File("-This is not a /nice\ file: no it isn't");

Some methods in other classes also return File objects, most notably the java.awt.FileDialog and javax.swing.JFileChooser methods discussed in the next chapter. Using file dialogs or choosers to ask the user for a filename is preferable to hardcoding them or reading them from the command line because file dialogs properly handle cross-platform issues and the distinctions between relative and absolute paths.

One thing you may not have noticed about these constructors: since a File object does not represent a file as much as a filename, these constructors do not actually create files. To create a new file with Java, you can open a file output stream to the file or invoke the createNewFile( ) method.

In Java 1.2 and later, construction of a File object includes normalization. This process reads hardcoded pathnames and attempts to convert them to the conventions of the local platform. This improves compatibility with code that's making assumptions about filenames. For instance, if a Windows VM is asked to create a File object with the path /public/html/javafaq/course/week2/index.html, it actually sets the path field to public html javafaq courseweek2 index.html. The reverse process happens on Unix; backslashes are converted to forward slashes. Because it can only really normalize separators, not filesystem roots, this scheme works better for relative pathnames than absolute ones.

17.3.2. Listing the Roots

The static File.listRoots( ) method returns an array containing the roots of the filesystem as File objects:

public static File[] listRoots( )

On Unix, this array is likely to have length 1 and contain the single root /. On Windows, it probably contains all the drive letters mapped to one device or another, whether or not there's actually any media in the drive, e.g., A:, C:, D:, E:, F:, G:. If the security manager does not allow the program to read a particular root, that root is not included in the returned list. If the security manager does not allow the program to read any root, the returned list will have length zero. Do not assume the array returned by listRoots( ) necessarily has any members! null is returned if the list can't be determined at all. This is not the same thing as a zero-length array.

The list of roots may or may not contain drives that are mounted over the network. If the drive is mounted in such a fashion that it pretends to be a local drive, it probably will be in the list. If the filesystem does not look like a local drive, it probably won't appear in the list. For instance, on Windows, network drives mapped to letters appear, but drives with UNC pathnames do not. Example 17-1 is a very simple program to list the roots and print them.

Example 17-1. RootLister

import java.io.*; public class RootLister { public static void main(String[] args) { File[] roots = File.listRoots( ); for (int i = 0; i < roots.length; i++) { System.out.println(roots[i]); } } }

Here's the output produced by RootLister on my Windows NT system. A: is the floppy drive. This system doesn't have a second floppy, which would normally be B:. C:, D:, E:, and F: are all partitions of the primary hard drive that appear to be separate drives. G: is an external hard drive, and H: is the CD-ROM. I: is a Macintosh drive mounted over the LAN.

D:JAVAioexamples17>java RootLister A: C: D: E: F: G: H: I:

The output on Unix (including Mac OS X) is much simpler and is virtually guaranteed to look like this:

$ java RootLister /

 

17.3.3. Listing Information about a File

The File class contains many methods that return particular information about the file. Most of this information can be gleaned from the path field alone without accessing the filesystem. Therefore, most of these methods do not throw IOExceptions.

17.3.3.1. Does the file exist? Is it a normal file? Is it a directory?

Since a File object does not necessarily correspond to a real file on the disk, the first question you'll probably want to ask is whether the file corresponding to the File object actually exists. This is especially important if you're relying on a user to type a filename rather than select it from a dialog because users routinely mistype filenames. The exists( ) method returns true if the file named in this file object's path field exists or false if it doesn't:

public boolean exists( )

There are two other ways to ask this question. The isFile( ) method returns TRue if the file exists and is not a directory. On the other hand, the isDirectory( ) method returns true if the file exists and is a directory.

public boolean isFile( ) public boolean isDirectory( )

The isDirectory( ) method considers Unix symbolic links and Mac aliases to directories to be directories themselves; it does not consider Windows shortcuts to directories to be directories. All three of these methods throw a security exception if the security manager does not allow the specified file to be read. In fact, if the file couldn't be read if it did exist, isDirectory( ) tHRows an exception whether the file actually exists or not. Revealing whether certain files exist can be a security violation.

17.3.3.2. Filename and path

The getName( ) method takes no arguments and returns the name of the file as a string:

public String getName( )

The name does not include any part of the directory in which the file lives. That is, you get back index.html instead of /public/html/javafaq/index.html. If the file is a directory like /public/html/javafaq/, only the last name is returned (javafaq in this example).

The getPath( ) method returns the complete path to the file:

public String getPath( )

This simply returns the path field. Therefore, the path is relative if the File object was constructed with a relative path and absolute if the File object was constructed with an absolute path. Furthermore, this method never throws IOExceptions. Consider Example 17-2. This simple program constructs two File objects, one with a relative path and one with an absolute path, and prints the name and path of each object.

Example 17-2. Paths

import java.io.*; public class Paths { public static void main(String[] args) { File absolute = new File("/public/html/javafaq/index.html"); File relative = new File("html/javafaq/index.html"); System.out.println("absolute: "); System.out.println(absolute.getName( )); System.out.println(absolute.getPath( )); System.out.println("relative: "); System.out.println(relative.getName( )); System.out.println(relative.getPath( )); } }

When the program is run on Unix, here's the output:

$ java Paths absolute: index.html /public/html/javafaq/index.html relative: index.html html/javafaq/index.html

On Windows the output is a little different because the File constructor normalizes the file separator character to the backslash:

D:JAVAioexamples17>java Paths absolute: index.html publichtmljavafaqindex.html relative: index.html htmljavafaqindex.html

 

17.3.3.3. Absolute paths

The getAbsolutePath( ) method returns the complete path to the file starting from a filesystem root:

public String getAbsolutePath( )

Examples of absolute paths include /public/html/javafaq/index.html and D:JAVAioexamples17 but not html/javafaq/index.html or ioexamples17. If the File object's path field is already an absolute path, its value is returned. Otherwise, a separator character and the value of the path field are appended to the value of the system property user.dir, which refers to the current working directory. This method throws a security exception when run from untrusted code because untrusted code cannot normally read the user.dir property.

If you need to know whether a file is specified by a relative or absolute path, you can call isAbsolute( ):

public boolean isAbsolute( )

This does not throw any security exceptions because it does not need to go outside the class to determine whether or not a pathname is absolute. Instead, the check is performed by looking at the first few characters of the path field. On Unix, an absolute path begins with a /. On Windows or OS/2, an absolute path begins with a capital letter followed by a colon and a backslash, like C:.

17.3.3.4. Canonical paths

Exactly what a canonical path is, and how it differs from an absolute path, is system-dependent, but it tends to mean that the path is somehow more real than the absolute path. Typically, if the full path contains aliases, shortcuts, shadows, or symbolic links of some kind, the canonical path resolves those aliases to the actual directories they refer to. The canonical path is returned by the getCanonicalPath( ) method:

public String getCanonicalPath( ) throws IOException

For example, suppose /bin/perl is a symbolic link to the real file at /usr/local/bin/perl, and you construct a File object perlLink like this:

File perlLink = new File("/bin/perl");

perlLink.getAbsolutePath( ) returns /bin/perl, but perlLink.getCanonicalPath( ) returns /usr/local/bin/perl.

getCanonicalPath( ) only resolves symbolic links. It does not resolve hard links. That is, it resolves links created with "ln -s file link" but not "ln file link."

getCanonicalPath( ) also removes relative references like the double period (..), which refers to the parent directory in paths. For instance, suppose the current working directory is /home/elharo/javaio/ioexamples/17.Then you create a File object like this:

File f = new File("../11/index.html"); String absolutePath = f.getAbsolutePath( ); String canonicalPath = f.getCanonicalPath( );

absolutePath is now /home/elharo/javaio/ioexamples/17/../11/index.html. However, canonicalPath is /home/elharo/javaio/ioexamples/11/index.html.

On Windows, getCanonicalPath( ) normalizes the case of two paths so that C:DocumentsBooks and C:DOCUMENTSBOOKS are recognized as the same path. Mac OS X also normalizes the case. Other Unixes with case sensitive filesystems do not. Usually, the normalized form is whatever was initially provided for the file's name.

One use for canonical paths is to test whether two files are the same. You might need to do this if you're reading from an input file and writing to an output file. While it might occasionally be possible to read from and write to the same file, doing so always requires special care. For example, the FileCopier program from Example 4-2 in Chapter 4 failed when the source and destination were the same file. Now we can use canonical paths to correct that flaw by testing whether two files are the same before copying, as shown in Example 17-3. If the files are the same, no copy needs to take place.

Example 17-3. Safe FileCopier

import java.io.*; public class SafeFileCopier { public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("Usage: java FileCopier infile outfile"); } else copy(new File(args[0]), new File(args[1])); } public static void copy(File inFile, File outFile) throws IOException { if (inFile.getCanonicalPath().equals(outFile.getCanonicalPath( ))) { // inFile and outFile are the same; // hence no copying is required. return; } InputStream in = null; OutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(inFile)); out = new BufferedOutputStream(new FileOutputStream(outFile)); for (int c = in.read(); c != -1; c = in.read( )) { out.write(c); } } finally { if (in != null) in.close( ); if (out != null) out.close( ); } } }

I could test the files themselves, but since a single file may have multiple paths through aliases or parent links, I'm still not guaranteed that the inFile and outFile aren't the same. But each file has exactly one unique canonical path, so if inFile's canonical path is not equal to outFile's canonical path, they can't possibly be the same file. Conversely, if inFile's canonical path is equal to outFile's canonical path, they must be the same file.

The getCanonicalFile( ) method acts just like getCanonicalPath( ), except that it returns a new File object instead of a string:

public File getCanonicalFile( ) throws IOException

The File object returned has a path field that's the canonical path of the file. Both getCanonicalPath( ) and getCanonicalFile( ) can throw IOExceptions because both need to read the filesystem to resolve aliases, shadows, symbolic links, shortcuts, and parent directory references.

17.3.3.5. Parents

The getParent( ) method returns a string containing everything before the last file separator in the path field:

public String getParent( )

For example, if a File object's path field is /home/users/elharo/javaio/ioexamples/11/index.html, getParent( ) returns /home/users/elharo/javaio/ioexamples/11. If a File object's path field is 11/index.html, getParent( ) returns 11. If a File object's path field is index.html, getParent( ) returns null. Filesystem roots have no parent directories. For these files, getParent( ) returns null.

The getParentFile( ) method does the same thing, except that it returns the parent as a new File object instead of a string:

public File getParentFile( )

 

17.3.3.6. File attributes

The File class has several methods that return information about the file, such as its length, the time it was last modified, whether it's readable, whether it's writable, and whether it's hidden.

The canWrite( ) method indicates whether the program can write into the file referred to by this File object. The canRead( ) method indicates whether the program can read from the file.

public boolean canRead( ) public boolean canWrite( )

Both these methods perform two checks. The first check determines whether Java's security manager allows the file in question to be read or written; the second determines whether the operating system allows the file to be read or written. If Java's security manager disallows the access, a security exception is thrown. If the OS disallows the access, the method returns false but does not throw any exceptions. However, attempting to read from or write to such a file will almost certainly throw an IOException.

Java 6 adds a canExecute( ) method that tests whether the current application can execute the file represented by the File object:

public boolean canExecute( ) // Java 6

Like canRead( ) and canWrite( ), this method does not merely check the execute bit. The question is whether the current program can launch the file (e.g., by Runtime's exec( ) methods).

The isHidden( ) method returns true if the file exists but is hidden; that is, it does not appear in normal displays or listings. It returns false if the file isn't hidden or doesn't exist.

public boolean isHidden( )

Exactly how a file is hidden varies from platform to platform. On Unix, any file whose name begins with a period is hidden. On Windows, hidden files are identified by particular attributes. This method throws a security exception if the security manager doesn't allow the file to be read.

The lastModified( ) method returns a long indicating the last time this file was modified:

public long lastModified( )

The time is the number of milliseconds since midnight, January 1, 1970, Greenwich Mean Time. However, in older VMs the conversion between this long and a real date is platform-dependent, so it's only useful for comparing the modification dates of different files, not for determining the absolute time a file was modified. This method throws a security exception if the security manager doesn't allow the file to be read. It returns 0 if the file doesn't exist or the last modified date can't be determined.

Finally, the length( ) method returns the number of bytes in the file or 0 if the file does not exist:

public long length( )

This method throws a security exception if the security manager doesn't allow the file to be read.

17.3.3.7. An example

Example 17-4 is a character-mode program that lists all the available information about files named on the command line. Names may be given as absolute or relative paths.

Example 17-4. The FileSpy program

import java.io.*; import java.util.*; public class FileSpy { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { File f = new File(args[i]); if (f.exists( )) { System.out.println("Name: " + f.getName( )); System.out.println("Absolute path: " + f.getAbsolutePath( )); try { System.out.println("Canonical path: " + f.getCanonicalPath( )); } catch (IOException ex) { System.out.println("Could not determine the canonical path."); } String parent = f.getParent( ); if (parent != null) { System.out.println("Parent: " + f.getParent( )); } if (f.canWrite()) System.out.println(f.getName( ) + " is writable."); if (f.canRead()) System.out.println(f.getName( ) + " is readable."); if (f.isFile( )) { System.out.println(f.getName( ) + " is a file."); } else if (f.isDirectory( )) { System.out.println(f.getName( ) + " is a directory."); } else { System.out.println("What is this?"); } if (f.isAbsolute( )) { System.out.println(f.getPath( ) + " is an absolute path."); } else { System.out.println(f.getPath( ) + " is not an absolute path."); } long lm = f.lastModified( ); if (lm != 0) System.out.println("Last Modified at " + new Date(lm)); long length = f.length( ); if (length != 0) { System.out.println(f.getName( ) + " is " + length + " bytes long."); } } else { System.out.println("I'm sorry. I can't find the file " + args[i]); } } } }

Here's the result of running FileSpy on itself:

D:JAVAioexamples17>java FileSpy FileSpy.java Name: FileSpy.java Absolute path: D:JAVAioexamples17FileSpy.java Canonical path: D:Javaioexamples17FileSpy.java FileSpy.java is writable. FileSpy.java is readable. FileSpy.java is a file. FileSpy.java is not an absolute path. Last Modified at Fri Sep 11 15:11:24 PDT 1998 FileSpy.java is 1846 bytes long.

 

17.3.4. Manipulating Files

The File class has methods to create, move, rename, and delete files. A method to copy files is a noticeable omission.

17.3.4.1. Creating files

The createNewFile( ) method creates the file referenced by the File object:

public boolean createNewFile( ) throws IOException

This method checks to see whether the file exists and creates the file if it doesn't already exist. It returns true if the file was created and false if it wasn't created, either because it couldn't be created or because the file already existed. For example:

File f = new File("output.dat"); boolean success = f.createNewFile( ); if (success) { //... } else { //...

This method throws an IOException if an I/O error occurs. It throws a security exception if the security manager vetoes the creation of the file.

17.3.4.2. Moving and renaming files

The renameTo( ) method changes the name of a file:

public boolean renameTo(File destination)

For example, to change the name of the file src.txt in the current working directory to dst.txt, you would write:

File src=new File("src.txt"); File dst = new File("dst.txt"); src.renameTo(dst);

If a file already exists with the destination name, the existing file may be overwritten or the rename may fail and return false. This varies from one platform and VM to another.

If the destination file is in a different directory than the source file, the renameTo( ) may move the source file from its original directory to the directory specified by the destination argument. For example, to move a file src to the directory /usr/tmp on a Unix system without changing the file's name, do this:

File dest = new File("/usr/tmp/" + src.getName( )); src.renameTo(dest);

However, this behavior is unreliable and platform-dependent. For instance, renameTo( ) moves files if, and only if, the directory structure specified in the dest File object already exists. I've also seen this code work on some Unix versions with some versions of the JDK and fail on others. It's best not to rely on this method for more than renaming a file in the same directory.

If src is successfully renamed, the method returns true. If the security manager doesn't allow the program to write to both the source file and the destination file, renameTo( ) throws a security exception. Otherwise, it returns false. Be sure to check this. Renaming is one of the more flaky areas of Java.

Copying Files

There is no copy( ) method that merely copies a file to a new location without removing the original. However, you can open a file output stream to the copy, open a file input stream from the original file, and copy the data byte by byte from the original into the copy. For example, to copy the file src to the file dst:

FileInputStream in = new FileInputStream(src); FileOutputStream out = new FileOutputStream(dst); for (int c = in.read(); c != -1; c = in.read( )) { out.write(c); } in.close( ); out.close( );  

There are some serious problems with this code. First of all, it assumes that both src and dst refer to files, not directories. Second, it only copies the contents of the files. If the file is associated with metainformation or extra data, that data is lost.

 

17.3.4.3. Deleting files

The delete( ) method removes files from the filesystem permanently:

public boolean delete( )

This method returns true if the file existed and was deleted. (You can't delete a file that doesn't exist.) If the security manager disallows this action, a security exception is thrown. Otherwise, delete( ) returns false.

17.3.4.4. Changing file attributes

The setLastModified( ) method changes a file's last modified time:

public boolean setLastModified(long time)

The time argument is the number of milliseconds since midnight, GMT, January 1, 1970. This is converted to the format necessary for a particular platform's file modification times. If the platform does not support millisecond-accurate file modification times, the time is rounded to the nearest time the host platform does support. This method throws an IllegalArgumentException if time is negative; it throws a SecurityException if the security manager disallows write access to the file.

The setReadOnly( ) method marks the file so that writing to the file is disallowed:

public boolean setReadOnly( )

Java 6 adds several more methods for changing a file's attributes. You can mark a file readable, writable, or executable:

public boolean setReadable(boolean executable) // Java 6 public boolean setWritable(boolean executable) // Java 6 public boolean setExecutable(boolean executable) // Java 6

Passing true makes the file readable, writable, and executable by the file's owner; passing false does the opposite. Changing these attributes may not always be possible. These methods return TRue if the file now has the requested attribute value or false if it doesn't. These methods can also throw a SecurityException if the security manager disallows access to the file.

You can pass false as the second argument to these methods to indicate that the file should be readable, writable, and executable by everyone, not just the file's owner:

public boolean setReadable(boolean executable, boolean ownerOnly) // Java 6 public boolean setWritable(boolean executable, boolean ownerOnly) // Java 6 public boolean setExecutable(boolean executable, boolean ownerOnly) // Java 6

Java has no concept of Unix group access, though.

17.3.5. Temporary Files

The File class provides two methods that create temporary files that exist only as long as the program runs:

public static File createTempFile(String prefix, String suffix) throws IOException public static File createTempFile(String prefix, String suffix, File directory) throws IOException

The createTempFile( ) methods create a file with a name that begins with the specified prefix and ends with the specified suffix. The prefix is a string used at the beginning of all temporary filenames; the suffix is appended to the end of all temporary filenames. The suffix may be null. If so, .tmp is used as the suffix. The same run of the same VM does not create two files with the same name. For example, consider this for loop:

for (int i=0; i < 10; i++) { File.createTempFile("mail", ".tem"); }

When run, it creates files named something like mail30446.tem, mail30447.tem, etc. through mail30455.tem.

By default, temporary files are placed in the directory named by the java.io.tmpdir property. On Unix, this is likely to be /tmp or /var/tmp. On Windows, it's probably C: emp or C:WindowsTemp. On Mac OS X, it's probably /private/tmp. You can specify a different directory using the third argument to createTempFile( ). For instance, this code fragment creates a temporary file in the current working directory:

File cwd = new File(System.getProperty("user.dir")); File temp = File.createTempFile("rus", ".tmp", cwd);

You often want to delete temporary files when your program exits. You can accomplish this by passing them to the deleteOnExit( ) method:

public void deleteOnExit( )

For example:

File temp = File.createTempFile("mail", ".tem"); temp.deleteOnExit( );

This method works on any File object, not just temporary files. Be careful because there's no good way to cancel a request to delete files.

Temporary files are useful when you need to operate on a file in place. You can do this in two passes. In the first pass, read from the file you're converting and write into the temporary file. In the second pass, read from the temporary file and write into the file you're converting. Here's an example:

File infile = new File(args[2]); File outfile = new File(args[3]); boolean usingTempFile = false; if (infile.getCanonicalPath().equals(outfile.getCanonicalPath( ))) { outfile = File.createTempFile("temp", null); outfile.deleteOnExit( ); usingTempFile = true; } // perform operations as normal, then close both files... if (usingTempFile) { FileInputStream fin = new FileInputStream(outfile); FileOutputStream fout = new FileOutputStream(infile); for (int c = fin.read(); c != -1; c = fin.read( )) { fout.write(c); } fin.close( ); fout.close( ); }

 

17.3.6. Checking for Free Space/Java 6

Java 6 adds three methods to inspect the amount of available and used space on a particular partition. A File object is used to choose the partition but otherwise it has no effect on the value returned. Two files on the same partition would give the same answers.

The getTotalSpace( ) method returns the size of the file's partition in bytes:

public long getTotalSpace( )

The getFreeSpace( ) method returns the total amount of empty space on the file's partition in bytes:

public long getFreeSpace( )

If the file does not exist, these methods return 0. They do not throw an exception. The number returned by this method is approximate. Depending on the nature of the filesystem, you may not be able to use all the bytes for a single file. For instance, some filesystems have maximum file sizes. The getUsableSpace( ) method makes a slightly better effort to find out how much space you can actually use.

public long getUsableSpace( )

It accounts for details like read-only filesystems that getFreeSpace( ) may not. However, the number it returns is still only approximate.

Even Java 6 doesn't have any reliable means to list all the partitions on a disk or to determine which partition you're on. If you happen to know the locations of files on each partition, these methods tell you how much space is left on each one. Normally, you have a single directory where a file will be saved and what you want to know is how much space is left on that directory's partition.

Example 17-5 is a simple program that lists the total, free, and usable space on the partition that contains the current working directory:

Example 17-5. Listing available space on the current partition

import java.io.*; public class CWDSpace { public static void main(String[] args) { File cwd = new File("."); System.out.println("Total space on current partition: " + cwd.getTotalSpace( ) / (1024 * 1024) + " MB "); System.out.println("Free space on current partition: " + cwd.getFreeSpace( ) / (1024 * 1024) + " MB "); System.out.println("Usable space on current partition: " + cwd.getUsableSpace( ) / (1024 * 1024) + " MB"); } }

Here's the output when I ran this on my Linux box from a directory in the /home partition:

$ java CWDSpace Total space on current partition: 6053 MB Free space on current partition: 2601 MB Usable space on current partition: 2293 MB

If I had to save a large file in this directory, I could save around two gigabytes. Anything much larger and I'd have to free up some space first.

17.3.7. Directories

A File object can represent a directory as easily as a file. Most of the File methods like getName( ), canWrite( ), and getPath( ) behave exactly the same for a directory as they do for a file. However, a couple of methods in the File class behave differently when they operate on directories than they do when operating on ordinary files.

The delete( ) method only works on empty directories. If a directory contains even one file, it can't easily be deleted. If you attempt to delete a nonempty directory, delete( ) fails and returns false. No exception is thrown.

The renameTo( ) method works on both empty and nonempty directories. Howeverwhether a directory is empty or notrenameTo( ) can only rename it, not move it to a different directory. If you attempt to move a directory into another directory, renameTo( ) fails and returns false. No exception is thrown.

The File class also has several methods that just work with directories, not with regular files.

17.3.7.1. Creating directories

The createNewFile( ) doesn't work for directories. For that purpose, the File class has a mkdir( ) method:

public boolean mkdir( )

The mkdir( ) method attempts to create a directory with the path specified in the path field. If the directory is created, the method returns TRue. For example:

File f = new File("tmp/"); f.mkdir( );

The trailing slash is optional, but it helps you to remember that you're dealing with a directory rather than a plain file. If the security manager does not allow the directory to be created, mkdir( ) throws a security exception. If the directory cannot be created for any other reason, mkdir( ) returns false. The mkdir( ) method only works for single directories. Trying to create a directory like com/elharo/io/ with mkdir( ) only works if com/elharo already exists.

The mkdirs( ) method creates every directory in a path that doesn't already exist:

public boolean mkdirs( )

For example:

File f = new File("com/elharo/io/"); f.mkdirs( );

mkdirs( ) returns true if all directories in this path are created or already exist and false if only some or none of them are created. If mkdirs( ) returns false, you need to test each directory in the path to see whether it was created because the invocation could have been partially successful.

One reason mkdir( ) and mkdirs( ) may return false (fail to create a directory) is that a file already exists with the name the directory has. Neither mkdir( ) nor mkdirs( ) will overwrite an existing file or directory.

17.3.7.2. Listing directories

The list( ) method returns an array of strings containing the names of each file in the directory referred to by the File object:

public String[] list( )

This method returns null if the File object doesn't point to a directory. It throws a security exception if the program isn't allowed to read the directory being listed. An alternative version of list( ) uses a FilenameFilter object (discussed later in the chapter) to restrict which files are included in the list:

public String[] list(FilenameFilter filter)

Example 17-6 is a simple character-mode program that recursively lists all the files in a directory, and all the files in directories in the directory, and all the files in directories in the directory, and so on. Files are indented two spaces for each level deep they are in the hierarchy.

Example 17-6. The DirList program

import java.io.*; import java.util.*; public class DirList { private File directory; private int indent = 2; private static List seen = new ArrayList( ); public static void main(String[] args) throws IOException { DirList dl = new DirList(args[0]); dl.list( ); } public DirList(String name) throws IOException { this(new File(name), 2); } public DirList(File f) throws IOException { this(f, 2); } public DirList(File directory, int indent) throws IOException { if (directory.isDirectory( )) { this.directory = new File(directory.getCanonicalPath( )); } else { throw new IOException(directory.toString( ) + " is not a directory"); } this.indent = indent; String spaces = ""; for (int i = 0; i < indent-2; i++) spaces += " "; System.out.println(spaces + directory + File.separatorChar); } public void list( ) throws IOException { if (!seen.contains(this.directory)) { seen.add(this.directory); String[] files = directory.list( ); String spaces = ""; for (int i = 0; i < indent; i++) spaces += " "; for (int i = 0; i < files.length; i++) { File f = new File(directory, files[i]); if (f.isFile( )) { System.out.println(spaces + f.getName( )); } else { // it's another directory DirList dl = new DirList(f, indent + 2); dl.list( ); } } } } }

Special care has to be taken to make sure this program doesn't get caught in an infinite recursion. If a directory contains an alias, shadow, shortcut, or symbolic link that points to one of its own parents, there's potential for infinite recursion. To avoid this possibility, all paths are converted to canonical paths in the constructor, and these paths are stored in the static list seen. A directory is listed only if it has not yet been traversed by this program.

17.3.7.3. The listFiles( ) methods

The two list( ) methods return arrays of strings. The strings contain the names of files. You can use these to construct File objects. Java allows you to eliminate the intermediate step of creating File objects by providing two listFiles( ) methods that return arrays of File objects instead of arrays of strings.

public File[] listFiles( ) public File[] listFiles(FilenameFilter filter) public File[] listFiles(FileFilter filter)

The no-argument variant of listFiles( ) simply returns an array of all the files in the given directory. The other two variants return the files that pass through their filters. File and filename filters will be discussed shortly.

17.3.8. File URLs

File URLs locate a file on the local filesystem. (Very early web browsers used file URLs to refer to FTP sites. However, that usage has long since disappeared.) They have this basic form:

file:///

should be the fully qualified domain name of the system on which the is found, though if it's omitted, the local host is assumed. is the hierarchical path to the file, using a forward slash as a directory separator (regardless of host filename conventions) and URL encoding of any special characters in filenames that would normally be encoded in a URL. Examples of file URLs include:

file:///C|/docs/JCE%201.2%20beta%201/guide/API_users_guide.html file:///D:/JAVA/ file:///usr/local/java/docs/JCE%201.2%20beta%201/guide/API_users_guide.html file:///D%7C/JAVA/ file:///Macintosh%20HD/Java/Cafe%20%au%20%Lait/course/week4/01.5.html file:/Users/elharo/Documents/books/Java%20IO%20 2/

Many web browsers allow other, nonstandard formats like:

file:///C|/jdk2beta4/docs/JCE 1.2 beta 1/guide/API_users_guide.html file:///C:jdk1.2beta4docsJCE 1.2 beta 1guideAPI_users_guide.html file:/D:/Java/ioexamples/17/FileDialogApplet.html file:/Users/elharo/Documents/books/Java IO 2/

Because of the differences between file and directory names from one computer to the next, the exact syntax of file URLs is unpredictable from platform to platform and web browser to web browser. The File class has a toURL( ) method that returns a file URL that's appropriate for the local platform:

public URL toURL( ) throws MalformedURLException

However, this method does not properly escape non-ASCII and non-URL-legal characters such as the space so it's been deprecated as of Java 1.4 and replaced by the toURI( ) method:

public URI toURI( )

toURI( ) isn't perfect, but it does a better job than toURL( ), and you should use it if it's available.

Категории