226

What is the difference between using File.separator and a normal / in a Java Path-String?

In contrast to double backslash \\ platform independence seems not to be the reason, since both versions work under Windows and Unix.

public class SlashTest {
    @Test
    public void slash() throws Exception {
        File file = new File("src/trials/SlashTest.java");
        assertThat(file.exists(), is(true));
    }

    @Test
    public void separator() throws Exception {
        File file = new File("src" + File.separator + "trials" + File.separator + "SlashTest.java");
        assertThat(file.exists(), is(true));
    }
}

To rephrase the question, if / works on Unix and Windows, why should one ever want to use File.separator?

Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
Joe23
  • 5,683
  • 3
  • 25
  • 23

14 Answers14

357

You use File.separator because someday your program might run on a platform developed in a far-off land, a land of strange things and stranger people, where horses cry and cows operate all the elevators. In this land, people have traditionally used the ":" character as a file separator, and so dutifully the JVM obeys their wishes.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 4
    Yup, Pointy really tooks us in elbonia (hope he has no pointy haircut ;-) (geek pun inside) – Riduidel Mar 10 '10 at 14:28
  • 9
    *"...and cows operate all the elevators."* Just as well I wasn't taking a sip of my coffee when I read that. Brilliant. – T.J. Crowder Mar 10 '10 at 16:13
  • 12
    In such a country you would make use of the new org.apache.chicken.elevators.OperatorUtility class, which embeds all this craziness for your convenience. – Brain Jun 11 '15 at 12:31
  • 1
    I was not aware cows operated the elevators at Apple before 2000: https://retrocomputing.stackexchange.com/questions/17069/why-did-macos-classic-choose-the-colon-as-a-path-separator – Arne Burmeister Nov 30 '21 at 14:48
  • @ArneBurmeister to be honest it's an exploitative practice – Pointy Nov 30 '21 at 14:50
269

With the Java libraries for dealing with files, you can safely use / (slash, not backslash) on all platforms. The library code handles translating things into platform-specific paths internally.

You might want to use File.separator in UI, however, because it's best to show people what will make sense in their OS, rather than what makes sense to Java.

Update: I have not been able, in five minutes of searching, to find the "you can always use a slash" behavior documented. Now, I'm sure I've seen it documented, but in the absense of finding an official reference (because my memory isn't perfect), I'd stick with using File.separator because you know that will work.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    This also might be a problem with the performance, since you are expecting the separator to be converted into something else at runtime. Also, do not expect this to happen in all the unsupported JVM's out there. – jpabluz Mar 10 '10 at 14:28
  • 8
    @T.J. Crowder: "I have not been able, in five minutes of searching, to find the 'you can always use a slash' behavior documented." It's not a feature of the JVM, it's a feature of Windows NT API. – Powerlord Mar 10 '10 at 14:36
  • @jpabluz: A library implementation (not JVM) that doesn't do this is an implementation that's likely to fail miserably at running a wide variety of software. I very much doubt you'll find one in the wild. – T.J. Crowder Mar 10 '10 at 14:41
  • 13
    @Powerlord: If Windows does it as well, great -- but the library (not the JVM) does it as well. Specifically, `File` uses `FileSystem.normalize` all over the place to "normalize" paths received via the public API, and nearly anything that deals with file path strings (for instance, `FileWriter(String)`) uses `File` under the covers. – T.J. Crowder Mar 10 '10 at 14:42
  • 11
    Since Java7 there is no need using File.separator anymore. It is much simpler and cleaner to use java.nio.file.Paths (Paths.get(first, more...)) for dir to dir and dir to filename joining. – magiccrafter Sep 17 '14 at 08:51
  • I used File.separator in mac it worked but it did not work in windows. Later I found that you must use "\" in case of APIs like getResourceAsStream. This is because it always expects path separated by "/" , thats wht File.separator only worked on mac. – Neil Nov 10 '14 at 15:50
  • 6
    @jpabluz 'A problem with performance'! Are you serious? Considering the uses filenames are put to on the disk, the runtime impact of a translation is utterly insignificant. It should be supported by any JVM, as it is part of the specification of `File`. – user207421 Mar 30 '16 at 09:19
  • @T.J.Crowder Could you please update the answer with the details of where it's being normalized (`File`) as per your comment? Also, is the whole "update" part of the answer no longer needed, or am I reading your comment wrong way? Thanks. (I'd edit myself but I'm not sure I understood correctly) – Jiri Tousek Oct 10 '19 at 19:57
29

Although using File.separator to reference a file name is overkill (for those who imagine far off lands, I imagine their JVM implementation would replace a / with a : just like the windows jvm replaces it with a \).

However, sometimes you are getting the file reference, not creating it, and you need to parse it, and to be able to do that, you need to know the separator on the platform. File.separator helps you do that.

Yishai
  • 90,445
  • 31
  • 189
  • 263
17

OK let's inspect some code.
File.java lines 428 to 435 in File.<init>:

String p = uri.getPath();
if (p.equals(""))
    throw new IllegalArgumentException("URI path component is empty");

// Okay, now initialize
p = fs.fromURIPath(p);
if (File.separatorChar != '/')
p = p.replace('/', File.separatorChar);

And let's read fs/*(FileSystem)*/.fromURIPath() docs:

java.io.FileSystem
public abstract String fromURIPath(String path)
Post-process the given URI path string if necessary. This is used on win32, e.g., to transform "/c:/foo" into "c:/foo". The path string still has slash separators; code in the File class will translate them after this method returns.

This means FileSystem.fromURIPath() does post processing on URI path only in Windows, and because in the next line:

p = p.replace('/', File.separatorChar);

It replaces each '/' with system dependent seperatorChar, you can always be sure that '/' is safe in every OS.

Alireza Mohamadi
  • 751
  • 1
  • 6
  • 22
8

Well, there are more OS's than Unix and Windows (Portable devices, etc), and Java is known for its portability. The best practice is to use it, so the JVM could determine which one is the best for that OS.

jpabluz
  • 1,200
  • 6
  • 16
  • Most of those OS's run some variant of UNIX. The old Mac style `:` separators have long since gone away. It seems that everyone but Windows uses the standard `/` anymore. And even windows seems to handle slashes fine now. Try `cd /windows/system` on a Windows 10 system from your main system drive. While you'd still want to display paths using the system separator (so as not to confuse your users) you can just use forward-slash `/` everywhere else and be confident that your code will work anywhere that you are likely to deploy it. – Shadow Man May 20 '19 at 20:09
7

Although it doesn't make much difference on the way in, it does on the way back.

Sure you can use either '/' or '\' in new File(String path), but File.getPath() will only give you one of them.

  • 1
    Slight correction... In **Windows** you can use either forward `/` or backward `\\ ` slash. But anywhere else, you better be using forward slash `/` or you will have issues. – Shadow Man May 20 '19 at 20:11
7

Late to the party. I'm on Windows 10 with JDK 1.8 and Eclipse MARS 1.
I find that

getClass().getClassLoader().getResourceAsStream("path/to/resource");

works and

getClass().getClassLoader().getResourceAsStream("path"+File.separator+"to"+File.separator+"resource");

does not work and

getClass().getClassLoader().getResourceAsStream("path\to\resource");

does not work. The last two are equivalent. So... I have good reason to NOT use File.separator.

i-make-robots
  • 95
  • 1
  • 1
  • 7
    In this line `getClass().getClassLoader().getResourceAsStream("path\to\resource");`, there are a tabulation (`\t`) and a carriage return (`\r`). – Stephan Feb 01 '16 at 22:08
  • 11
    That's a different scenario to the question. ClassLoader's getResourceAsStream method does not take a File path, but a _resource name_ which may or may not be on the file system and is [documented](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getResourceAsStream(java.lang.String)) as only accepting '/' as the resource path separator. – daiscog Nov 09 '16 at 16:59
  • @Stephan there is no funny escaping there, since `File.separator` is a backslash. It's only in hard-coded strings where it is treated as an escape character where you need to escape the backslash. If you've stored the character in a text file, or in a `char` or `String` then you don't need to escape it a 2nd time as it's already been converted to the expected backslash character. Try this to see for yourself: `String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");` – Shadow Man May 20 '19 at 20:19
  • 2
    @Stephan oh, I see... You were you talking about the 3rd line. You are correct. In that line (a hard-coded string) you would need to escape the escape character. My eyes stopped at the 2nd line and I didn't even notice the 3rd line at first. – Shadow Man May 20 '19 at 20:38
3

portability plain and simple.

Holograham
  • 1,348
  • 1
  • 13
  • 34
  • 1
    Yes, for portability, do **not** use backslash. Use forward slash `/` or the system separator `File.separator`. Both of those seem to work everywhere. While `File.separator` is guaranteed to work everywhere, the simple slash `/` also seems to work everywhere. If it doesn't work somewhere, then I'd love to hear about it. I believe it will work on all systems. At the very least, I have yet to find anywhere that `/` doesn't work (Mac OSX, Windows, *nix, Android, iOS -- I haven't checked pre OSX Macs that used ":" as a separator though, OS/2, NeXT, or any of the other really ancient OS's). – Shadow Man May 20 '19 at 20:29
1

"Java SE8 for Programmers" claims that the Java will cope with either. (pp. 480, last paragraph). The example claims that:

c:\Program Files\Java\jdk1.6.0_11\demo/jfc

will parse just fine. Take note of the last (Unix-style) separator.

It's tacky, and probably error-prone, but it is what they (Deitel and Deitel) claim.

I think the confusion for people, rather than Java, is reason enough not to use this (mis?)feature.

Erik Bennett
  • 1,049
  • 6
  • 15
1

As the gentlemen described the difference with variant details.

I would like to recommend the use of the Apache Commons io api, class FilenameUtils when dealing with files in a program with the possibility of deploying on multiple OSs.

E_X
  • 3,722
  • 1
  • 14
  • 15
0

The pathname for a file or directory is specified using the naming conventions of the host system. However, the File class defines platform-dependent constants that can be used to handle file and directory names in a platform-independent way.

Files.seperator defines the character or string that separates the directory and the file com- ponents in a pathname. This separator is '/', '\' or ':' for Unix, Windows, and Macintosh, respectively.

  • The ":" for Macintosh is ancient. Since OSX, Mac also uses "/" (forward slash) since it is running a form of UNIX with a standard UNIX filesystem under the hood. – Shadow Man May 20 '19 at 20:34
0

If you are using Java 7, checkout Path.resolve() and Paths.get().

ceilfors
  • 2,617
  • 23
  • 33
0

Using File.separator made Ubuntu generate files with "\" on it's name instead of directories. Maybe I am being lazy with how I am making files(and directories) and could have avoided it, regardless, use "/" every time to avoid files with "\" on it's name

Guedez
  • 189
  • 3
  • 14
0

If you are trying to create a File from some ready path (saved in database, per example) using Linux separator, what should I do?

Maybe just use the path do create the file:

new File("/shared/folder/file.jpg");

But Windows use a different separator (\). So, is the alternative convert the slash separator to platform independent? Like:

new File(convertPathToPlatformIndependent("/shared/folder"));

This method convertPathToPlatformIndependent probably will have some kind of split by "/" and join with File.separator.

Well, for me, that's not nice for a language that is platform independent (right?) and Java already support the use of / on Windows or Linux. But if you are working with paths and need to remember to this conversion every single time this will be a nightmare and you won't have any real gain for the application on the future (maybe in the universe that @Pointy described).

Dherik
  • 17,757
  • 11
  • 115
  • 164