6.5 File Separator

You should also learn to use characters in different operating systems to represent a directory path in a file hierarchy. The file separator is always a problem when dealing with multiple platforms.

Consider the following paths, all valid for their respective operating systems:

  • Windows: C:\myfolder\mydocument.txt

  • Unix: /usr/myuser/mydocument.txt

  • Classic Mac OS: Hard Drive:My Folder:My Document

Each path describes a typical location for a user document, located in a nested folder. Each OS uses a different character to represent a directory: \, /, or :. Make sure your application does not make assumptions about which of these characters to use, but rather relies on the value returned by the system specific to that platform:


The file.separator is the system property containing the character (or characters) that delimits file and directory names. This character is usually / or \. The path.separator is the character used to separate path entries on a single line (such as multiple entries in the system's classpath).

Generally, either you will have a base directory and need to construct paths relative to this directory, or you will work with user-specified files and use standard file dialogs.

6.5.1 Class Loader Issues

When writing Java applications, it's common to write code that contains a reference to a platform-specific class and then dynamically load that class. Consider the following pseudo-code snippet:

    com.apple.system.Utility myAppleClass= new Utility(  );
    myAppleClass.beep(  );
} else

In the case above, even if the code is run on Windows (and therefore the ismacos variable never evaluates to true), the com.apple.system.Utility class will still be loaded by reference by the class loader, which in turn will throw a ClassDefNotFound or similar exception. At compile time, this action will create errors and can be caught and dealt with. However, developing on a system where the dynamically loaded class is present can be worse?in this case, compilation succeeds, and it isn't until the application is run on a different platform that errors occur. The result, unsurprisingly, is often an unhappy user.

One way to solve this problem is to place platform-specific code into another set of classes and then load them dynamically. There are a couple of strategies for dealing with this, depending on the range and scope of the classes to be loaded dynamically.

One strategy is simply to load a single class by name, construct method references, and then call that class as needed. Consider the following code snippet:

Class myClass = null;
    myClass = Class.forName("java.lang.String");
    java.lang.reflect.Method myMethod = myClass.getMethod("length", null);
    Object myString = myClass.getConstructor(null).newInstance(null);
    Object myResult = myMethod.invoke(myString, null);
} catch (Exception e)
    e.printStackTrace(  );
if(myClass == null)
    System.out.println("java.lang.String unavailable!");

Since there is no explicit reference to the class java.lang.String, if java.lang.String were unavailable, the application would merely report the exception and continue. Obviously, building the references to the various methods manually (not to mention the laboriousness of building the parameter lists) can become oppressive with this method. Therefore, you may wish to cast dynamically loaded objects to a specific, required interface, as the following code snippet (taken from Chapter 4) shows:

Class myClass = Class.forName(argsconfig[i]);
SimpleEditPlugin myPlugin =                    
// Call methods from the SimpleEditPlugin interface on myPlugin as you wish.