Download (direct link):
FileLock. Added to JDK 1.4, a class to represent a lock on a region of a file. A lock can be either exclusive or shared. These objects are safe for use by multiple threads but only apply to a single virtual machine.
Now let's narrow our focus to the File class. Listing 20.1 demonstrates some File class behaviors and pitfalls.
01: package org.javapitfalls.item20;
03: import java.io.*;
05: public class BadFileRename
07: public static void main(String args)
11: // check if test file in current dir
12: File f = new File("dummy.txt");
13: String name = f.getName();
14: if (f.exists())
15: System.out.println(f.getName() + " exists.");
17: System.out.println(f.getName() + 2
" does not exist.");
19: // Attempt to rename to an existing file
20: File f2 = new File("dummy.bin");
21: // Issue 1: boolean status return instead of Exceptions
22: if (f.renameTo(f2))
24: "Rename to existing File Successful.");
27: "Rename to existing File Failed.");
29: // Attempt to rename with a different extension
30: int dotldx = name.indexOf('.');
31: if (dotldx >= 0)
32: name = name.substring(0, dotldx);
33: name = name + ".tst";
34: String path = f.getAbsolutePath();
35: int lastSep = path.lastlndexOf(File.separator);
36: if (lastSep > 0)
Listing 20.1 BadFileRename.java (continued)
154 Item 20
37 path = path.substring(0,lastSep);
38 System.out.println("path: " + path);
39 File f3 = new File(path + File.separator + name);
40 System.out.println("new name: " + f3.getPath());
41 if (f.renameTo(f3))
43 "Rename to new extension Successful.");
46 "Rename to new extension failed.");
48 // delete the file
49 // Issue 2: Is the File class a file?
50 if (f.delete())
51 System.out.println("Delete Successful.");
53 System.out.println("Delete Failed.");
55 // assumes program not run from c drive
56 // Issue 3: Behavior across operating systems?
57 File f4 = new File("c:\\" + f3.getName());
58 if (f3.renameTo(f4))
"Rename to new Drive Successful.");
61 System.out.println("Rename to new Drive failed.");
62 } catch (Throwable t)
Listing 20.1 (continued)
When this code is run from a drive other than C, and with the file dummy.txt in the current directory, it produces the following output:
Rename to existing File Failed.
new name: E:\classes\org\javapitfalls\Item20\dummy.tst
Rename to new extension Successful.
Rename to new Drive Successful.
When File.renameTo() Won't 155
Listing 20.1 raises three specific issues, which are called out in the code comments. At least one is accurately characterized as a pitfall, and the others fall under poor design:
¦¦ First, returning a Boolean error result does not provide enough information about the failure's cause. That proves inconsistent with exception use in other classes and should be considered poor design. For example, the failure above could have been caused by either attempting to renameTo() a file that already exists or attempting to renameTo() an invalid filename. Currently, we have no way of knowing.
¦¦ The second issue is the pitfall: attempting to use the initial File object after a successful rename. What struck me as odd in this API is the use of a File object in the renameTo() method. At first glance, you assume you only want to change the filename. So why not just pass in a String? In that intuition lies the source of the pitfall. The pitfall is the assumption that a File object represents a physical file and not a file's name. In the least, that should be considered poor class naming. For example, if the object merely represents a filename, then it should be called Filename instead of File. Thus, poor naming directly causes this pitfall, which we stumble over when trying to use the initial File object in a delete() operation after a successful rename.
¦¦ The third issue is File.renameTo() 's different behavior between operating systems. The renameTo() works on Windows even across filesystems (as shown here) and fails on Solaris (reported in Sun's Bug Parade and not shown here). The debate revolves around the meaning of "Write Once, Run Anywhere" (WORA). Sun programmers verifying reported bugs contend that WORA simply means a consistent API. That is a cop-out. A consistent API does not deliver WORA; there are numerous examples in existing APIs where Sun went beyond a consistent API to deliver consistent behavior. The best-known example of this is Sun's movement beyond the Abstract Windowing Toolkit's consistent API to Swing's consistent behavior. If you claim to have a platform above the operating system, then a thin veneer of an API over existing OS functionality will not suffice. A WORA platform requires consistent behavior; otherwise, "run anywhere" means "maybe run anywhere." To avoid this pitfall, you check the "os.name" System property and code renameTo() differently for each platform.