确定文件是否是联结(在Windows中)?

Mar*_*tin 11 java windows winapi jna

我一直在寻找一种方法来确定文件是否是一个交汇点,并且没有找到任何令人满意的答案.

我尝试的第一件事是:

Files.isSymbolicLink(aPath)
Run Code Online (Sandbox Code Playgroud)

它仅检测符号链接,而不检测Windows中称为联结的文件.

还尝试了这里提出的解决方案(使用JNA库): Stackoverflow问题(3249117) ,但它永远不会在我知道的任何文件中返回true.

我发现确定哪些文件是联结的唯一方法是在Windows命令提示符下运行以下命令:

DIR /S /A:L
Run Code Online (Sandbox Code Playgroud)

在我的计算机上它返回66个文件夹,而且Files.isSymbolicLink(aPath)仅返回2.所以我想我可以找到一种方法来利用它,但我认为在遍历文件树时它不会非常有效.

有没有办法使用标准的java库,或者替代JNA?

jan*_*pol 7

没有JNA可以有一种方法,如果你有正确的java,比如Oracle jdk 8.它很狡猾,它可以停止工作,但....

您可以获得与链接相关的BasicFileAttributes接口:

BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
Run Code Online (Sandbox Code Playgroud)

可能会发生此接口实现是一个类 sun.nio.fs.WindowsFileAttributes.此类有一个方法isReparsePoint,对于连接点和符号链接都返回true.所以你可以尝试使用反射并调用方法:

    boolean isReparsePoint = false;
    if (DosFileAttributes.class.isInstance(attr))
        try {
            Method m = attr.getClass().getDeclaredMethod("isReparsePoint");
            m.setAccessible(true);
            isReparsePoint = (boolean) m.invoke(attr);
        } catch (Exception e) {
            // just gave it a try
        }
Run Code Online (Sandbox Code Playgroud)

现在你只能发现它是否真的是符号链接: Files.isSymbolicLink(path)

如果不是,但它是重新分析点,那就是那个结点.


ssc*_*rth 7

虽然在 Windows 上,结点的属性有isSymbolicLink()== false,但它们有isOther()== true。所以你可以这样做:

boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
BasicFileAttributes attrs = Files.readAttributes(aPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
boolean isJunction = isWindows && attrs.isDirectory() && attrs.isOther();
Run Code Online (Sandbox Code Playgroud)

  • 解决方案的可能来源:[JDK-8031083 Files.readAttributes() 未检测到 NTFS 连接点](https://bugs.openjdk.java.net/browse/JDK-8031083) (2认同)

Pet*_*ner 6

使用J2SE 1.7使用Java NIO

/**
* returns true if the Path is a Windows Junction
*/
private static boolean isJunction(Path p) {
    boolean isJunction = false;
    try {
        isJunction = (p.compareTo(p.toRealPath()) != 0);
    } catch (IOException e) {
        e.printStackTrace(); // TODO: handleMeProperly
    }
    return isJunction;
}
Run Code Online (Sandbox Code Playgroud)

  • @Peter 为什么这是预期的?尽管流行观点,路口不是硬链接。NTFS 具有硬链接、连接点和符号链接。符号链接和结点之间的区别与遍历结点不擅长的 UNC 目标有关。 (2认同)

Rem*_*eau 5

如果您可以在JNA中编写本机代码,则可以直接调用Win32 API GetFileAttributes()函数并检查FILE_ATTRIBUTE_REPARSE_POINT标志(联结实现为重新分析点).

更新:要区分不同类型的重新分析点,您必须检索ReparseTag实际重新分析点.对于连接点,它将设置为IO_REPARSE_TAG_MOUNT_POINT(0xA0000003).

有两种方法可以检索ReparseTag:

  1. DeviceIoControl()FSCTL_GET_REPARSE_POINT控制代码一起使用以获取REPARSE_DATA_BUFFER结构,该结构作为ReparseTag字段.您可以IsDirectoryJunction()在以下文章中看到使用此技术的实现示例:

    NTFS硬链接,目录连接和Windows快捷方式

  2. 使用FindFirstFile()获得WIN32_FIND_DATA结构.如果路径具有该FILE_ATTRIBUTE_REPARSE_POINT属性,则该dwReserved0字段将包含该属性ReparseTag.