44

In a DirectoryWalker class I want to find out if a File instance is actually a symbolic link to a directory (assuming, the walker walks on UNIX systems). Given, I already know the instance is a directory, would the following be a reliable condition to determine the symbolic link?

File file;
// ...      
if (file.getAbsolutePath().equals(file.getCanonicalPath())) {
    // real directory ---> do normal stuff      
}
else {
    // possible symbolic link ---> do link stuff
}
luk2302
  • 55,258
  • 23
  • 97
  • 137
mats
  • 1,818
  • 3
  • 18
  • 26
  • Related to http://stackoverflow.com/questions/2175673/java-check-symbolic-link-file-existence – Gray Apr 23 '12 at 19:27
  • 8
    Java 1.7: [java.nio.Files.isSymbolicLink(Path)](http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#isSymbolicLink%28java.nio.file.Path%29) - more a note for myself - I keep ending up back here! – Julius Musseau Nov 16 '12 at 20:39

7 Answers7

49

The technique used in Apache Commons uses the canonical path to the parent directory, not the file itself. I don't think that you can guarantee that a mismatch is due to a symbolic link, but it's a good indication that the file needs special treatment.

This is Apache code (subject to their license), modified for compactness.

public static boolean isSymlink(File file) throws IOException {
  if (file == null)
    throw new NullPointerException("File must not be null");
  File canon;
  if (file.getParent() == null) {
    canon = file;
  } else {
    File canonDir = file.getParentFile().getCanonicalFile();
    canon = new File(canonDir, file.getName());
  }
  return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}
Dwhitz
  • 1,250
  • 7
  • 26
  • 38
erickson
  • 265,237
  • 58
  • 395
  • 493
  • Hmm, Gray and erickson: in fact it seems to work fine even if it links to a file in the same directory. Do you have an unit test illustrating your point? – Kutzi Jan 08 '12 at 11:24
  • 7
    This does not work on Windows with NTFS (when symlink is created with mklink). – Ben Jun 28 '12 at 13:58
  • This has one problem in that it fails to discover symbolic links that point to missing files. I think there needs to be a `file.exists()` test here additionally. – Gray Sep 21 '22 at 21:56
15

Java 1.6 does not provide such low level access to the file system. Looks like NIO 2, which should be included in Java 1.7, will have support for symbolic links. A draft of the new API is available. Symbolic links are mentioned there, creating and following them is possible. I'm not exactly sure that which method should be used to find out whether a file is a symbolic link. There's a mailing list for discussing NIO 2 - maybe they will know.

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
14

Also, watch out for file.isFile() and file.isDirectory() both returning results based on the resolved file and therefore both returning false when file refers to a symlink where the target doesn't exist.

(I know this isn't a useful answer in itself but it tripped me up a couple of times so thought I should share)

Rob Oxspring
  • 2,835
  • 1
  • 22
  • 28
5

It looks like getCanonicalPath() can do other things that might make it different from the absolute path.

This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).

But it might work for the vast majority of your use cases; your mileage may vary.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
3

If you are already coding something specifically for *nix, then you could do a shell command from Java like this:

Process p = Runtime.getRuntime().exec(new String[]{"test", "-h", yourFileName});
p.waitFor();
if (p.exitValue() == 0) 
   System.out.println("This file is a symbolic link");
else
   System.out.println("This file is not a symbolic link");

That's very specific to *nix, but it does at least work.

Beaker
  • 744
  • 7
  • 18
1

Sorry to reply to such an old post, but I was looking for a solution for Windows systems some time back, and some of the previous answers didn't work out for me. If you're not concerned with cross platform compatibility and only need a solution for Windows, the following technique worked well for my purposes.

File f = new File("whatever file or folder");
if (f instanceof ShellFolder) {
  ShellFolder sf = (ShellFolder)f;
  if (sf.isLink()) {
    // Your code when it's a link
  }
}
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Ray Newman
  • 19
  • 1
  • 1
    `ShellFolder` seems to be `sun.awt.shell.ShellFolder` in `rt.jar` – sjngm Jul 07 '12 at 16:42
  • 3
    I dont think "new File()" will produce an instance of ShellFolder dynamically. It does work as a result of FileChoser. – eckes Oct 13 '14 at 00:58
-2

I thought I would share some good fortune I had in dealing with this issue. I am using JDK 1.6.0_23 and so I cannot benefit from NIO2. I am building and running on Windows 7 /x64 ONLY so mileage may vary in other environments. Unfortunately, other solutions here did not work for me in avoiding NullPointerExceptions caused when attempting to traverse a junction (probably because junction != symlink....). While I am not constrained by JDK version, I decided to keep at the problem for a bit longer.

I had this code which would cause a NullPointerException if used on a symbolic link or when encountering the 'System Volume Information' directory. (Note, traverseItem.f() returns an object of type java.io.File)

if (traverseItem.f().isDirectory) {
    for (File item : traverseItem.f().listFiles()) {

So, it is supposedly a directory but calling listFiles() on it causes an NPE. What to do? I spied the list() method and wondered if it would exhibit the same behavior. What I discovered was the following:

Calling list() on a File describing an empty folder returns a String[] array of length zero. However, calling list() on a File describing a junction which would otherwise crash from listFiles() returns null

I was able to avoid the NullPointerExceptions by adding the following test before calling listFiles()

    String[] contents = traverseItem.f().list();
    if (contents != null) {  //Non-traversible if null, possibly junction or ???

It remains to exhaustively test all cases of junction, symbolic link, hard link, and dare I mention it, shortcut, but this may help some.

user602347
  • 155
  • 1
  • 4
  • Your explanation is all over the place, seems almost entirely irrelevant in most places, mostly inaccurate in others, and your code snippets are massively incomplete. I'd give this 2 downvotes if I could. – searchengine27 Jul 25 '15 at 19:00