Java 1.6 - determine symbolic links

2019-01-01 09:17发布

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
}

标签: java java-6
7条回答
零度萤火
2楼-- · 2019-01-01 09:24

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.

查看更多
墨雨无痕
3楼-- · 2019-01-01 09:25

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.

查看更多
浮光初槿花落
4楼-- · 2019-01-01 09:28

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)

查看更多
与君花间醉酒
5楼-- · 2019-01-01 09:29

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());
}
查看更多
泪湿衣
6楼-- · 2019-01-01 09:31

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
  }
}
查看更多
几人难应
7楼-- · 2019-01-01 09:36

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.

查看更多
登录 后发表回答