tags:

views:

427

answers:

2

Right now we've got a hard-coded set of characters that we check for -- :*?"<>|/\ -- basically the ones Windows complains about. However, running on Linux, this is way too restrictive.

I know that in Java 7 NIO, the Path class is supposed to be smart enough to check this in an OS-dependent way, and throw an InvalidPathException if you specify an invalid filename. But we're not running Java 7. Is there an reliable way to do this in Java 6?

(Note that new File("foo:bar") in Windows does appear to work. But what you actually get if, for instance, try to use a FileWriter to write to your new File, is an empty file called foo. exists() on the File will return true at that point, but it's more or less lying.)

A: 

What about looking at Java7's sources and "backport" a small portion of that (for every OS you have to support) to Java6?

There should be a class for every system that extends Path. The sole source I could find quickly using Google CodeSearch(my query) is GaePath.java, which implements the path's thing for GaeVFS. I don't think GaeVFS interests you, but Java7's functions doing that for Win32/UNIX/... must be available somewhere (probably here or there).

Johannes Weiß
I poked around and found sun.nio.fs.WindowsPathParser, and sun.nio.fs.UnixPath, but neither one appears to do anything especially clever. Probably just as well given that my bosses wouldn't appreciate it if I copied/incorporated GPL code. :)
David Moles
A: 

For lack of anything clever, here's what I came up with -- the meat of it, anyway.

Strictly speaking, it's probably the combination of OS and filesystem that determines the invalid character set, but for my purposes a hack based simply on the OS seems to be good enough.

Also, these invalid character sets are empirical, not official. The Windows invalid characters are taken from the error message you get in XP when you try to rename a file on an NTFS volume to something invalid. For Unix/Linux, I think you can get away with pretty much anything except a path separator (please correct me if you know better). For MacOS, whether : or / is the path separator seems to depend on the filesystem -- for my purposes it's safest just to include both. (And hope they're not mounting FAT or NTFS.)

List<Integer> invalidIndices = new LinkedList<Integer>();

String invalidChars;
if (OS.isWindows()) {
    invalidChars = "\\/:*?\"<>|";
} else if (OS.isMacOSX()) {
    invalidChars = "/:";
} else { // assume Unix/Linux
    invalidChars = "/";
}

char[] chars = filename.toCharArray();
for (int i = 0; i < chars.length; i++) {
    if ((invalidChars.indexOf(chars[i]) >= 0) // OS-invalid
        || (chars[i] < '\u0020') // ctrls
        || (chars[i] > '\u007e' && chars[i] < '\u00a0') // ctrls
    ) {
        invalidIndices.add(i);
    }
}

return invalidIndices;

Note: this is using the SwingX OS utility class to determine the operating system, but if you don't have that, it doesn't do anything magical either -- just parses System.getProperty("os.name").

David Moles