【问题标题】:Cross platform way to detect a symbolic link / junction point?跨平台检测符号链接/连接点的方法?
【发布时间】:2010-07-14 18:13:21
【问题描述】:

在 java 中,可以通过比较文件的规范路径和绝对路径来检测 Unix 环境中的符号链接。但是,此技巧不适用于 Windows。如果我执行

mkdir c:\foo
mklink /j c:\bar

从命令行,然后在java中执行以下行

File f = new File("C:/bar");
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());

输出是

C:\bar
C:\bar

是否有任何 Java 7 之前的方法来检测 Windows 中的连接点?

【问题讨论】:

  • 您可以使用 JNI 方法获取文件属性并检查其是否为重解析点
  • 应该顺便补充一点,Java 7 也不会将连接检测为符号链接。

标签: java windows cross-platform


【解决方案1】:

在 Java 6 或更早版本中似乎没有任何跨平台机制,尽管使用 JNA 是一项相当简单的任务

interface Kernel32 extends Library {
  public int GetFileAttributesW(WString fileName);
}

static Kernel32 lib = null;
public static int getWin32FileAttributes(File f) throws IOException { 
  if (lib == null) {
    synchronized (Kernel32.class) {
      lib = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    }
  }
  return lib.GetFileAttributesW(new WString(f.getCanonicalPath()));
}

public static boolean isJunctionOrSymlink(File f) throws IOException {
  if (!f.exists()) { return false; }
  int attributes = getWin32FileAttributes(f);
  if (-1 == attributes) { return false; }
  return ((0x400 & attributes) != 0);
}

编辑:更新了getWin32FileAttributes()可能返回的错误评论

【讨论】:

  • 仅供参考,GetFileAttributesW() 如果失败,则返回0xFFFFFFFF-1 作为int)。 isJunctionOrSymlink() 需要先检查该条件,然后再检查 0x400 标志,否则将返回误报。由于如果文件不存在,GetFileAttributesW() 将失败,因此对f.exists() 的检查是多余的。
【解决方案2】:

答案是“不”。连接点和符号链接不是一回事。 JRE 不会检查它们,因此您引用的函数不会区分它们。

话虽如此,您可能会通过以下方式完成一些事情:

如果联结目录有内容,那么在其下方获取某些东西的规范路径名的结果可能会“令人惊讶”并揭示情况,因为它很可能是联结目标下的路径名。这仅适用于联结指向的目录当然是非空的。

【讨论】:

  • windows 中的连接点是一个文件系统实体,它将您重定向到另一个位置(可能在另一个卷上),并且对所有用于打开和读取文件的文件系统 API 都是透明的。这与(POSIX)符号链接有何不同?除了在 Windows 上,如果它用于目录,则称为 junction,如果用于文件,则称为符号链接?
  • 我的问题的重点是取消链接 linux 上的 JVM,windows 上的 JVM 不会为结点(或目录符号链接或其中的任何内容)返回不同的规范和绝对值。
  • 在 Linux 文件系统中,inode 中有一个指向真正父级的反向指针,而不是指向任何符号链接。类似地在 NTFS 中。 挂载点
【解决方案3】:

你可以试试这个肮脏的 Windows hack

    if (f.isDirectory() || f.isFile()) {
        System.out.println("File or Directory");
    } else {
        System.out.println("Link");
    }

【讨论】:

  • 这没什么用。 isDirectory() 将为普通目录、目录符号链接(使用 mklink /d 创建)或联结(使用 mklink /j 创建)返回 true。任何其他类型的链接或快捷方式都将为 isFile() 返回 true。您的困惑可能源于这样一个事实:如果您创建一个目录或文件的快捷方式,它显示为“Foo”,但在磁盘上它表示为“Foo.lnk”,因此 isDirectory() 和 isFile() 将返回 false 为 ' Foo' (但这样会存在())。无论如何,快捷方式只是一个 Windows 资源管理器工件,与我的要求无关。
猜你喜欢
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多