Java 确定文件是否为连接(在Windows中)?

Java 确定文件是否为连接(在Windows中)?,java,windows,winapi,jna,Java,Windows,Winapi,Jna,我一直在四处搜索,试图找到一种方法来确定一个文件是否为连接,但没有找到任何令人满意的答案 我尝试的第一件事是: Files.isSymbolicLink(aPath) 它只检测符号链接,而不检测Windows中称为连接的文件 还尝试了此处提出的解决方案(使用JNA库): ,但在我知道是连接的任何文件上都没有返回true 我发现确定哪些文件是连接的唯一方法是在windows命令提示符下运行以下命令: DIR /S /A:L 在我的电脑上,它返回66个文件夹和文件。isSymbolicLink(

我一直在四处搜索,试图找到一种方法来确定一个文件是否为连接,但没有找到任何令人满意的答案

我尝试的第一件事是:

Files.isSymbolicLink(aPath)
它只检测符号链接,而不检测Windows中称为连接的文件

还尝试了此处提出的解决方案(使用JNA库): ,但在我知道是连接的任何文件上都没有返回true

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

DIR /S /A:L
在我的电脑上,它返回66个文件夹和文件。isSymbolicLink(aPath)只返回2个。 所以我想我可以找到一种方法来利用它,但我不认为它在遍历文件树时会非常有效


有没有办法使用标准java库或JNA来实现这一点?

如果可以在JNA中编写本机代码,可以直接调用Win32 API
GetFileAttributes()
函数并检查
FILE\u ATTRIBUTE\u repasse\u POINT
标志(连接被实现为重分析点)

更新:要区分不同类型的重分析点,必须检索实际重分析点的
重分析标签
。对于连接点,它将被设置为
IO\u repasse\u TAG\u MOUNT\u point
(0xA0000003)

有两种方法可以检索
repassetag

  • 与控制代码一起使用以获取结构,该结构作为
    repassetag
    字段。您可以在下面的文章中看到使用此技术的
    IsDirectoryJunction()
    实现的示例:


  • 用于获取结构。如果路径具有
    FILE\u ATTRIBUTE\u repasse\u POINT
    属性,则
    dwReserved0
    字段将包含
    repassetag


  • 如果您有合适的java,比如OracleJDK8,那么可以在没有JNA的情况下实现这一点。这是不可靠的,它可以停止工作,但是

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

    BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
    
    这个接口实现可能是一个类
    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
            }
    
    现在您只能发现它是否真的是符号链接:
    Files.isSymbolicLink(path)


    如果不是,但它是重分析点,那么这就是连接点。

    对于J2SE1.7,使用JavaNIO

    /**
    * 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;
    }
    

    在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();
    

    谢谢,除了复制和粘贴代码,我以前从未真正使用过JNA,但如果这是我认为我最好学习的唯一方法。你的建议似乎与我发布的链接中的建议相似,如果您能为我提供一个如何检查重分析标志的示例,我将不胜感激。
    FILE\u ATTRIBUTE\u repasse\u POINT
    定义为
    0x400
    ,因此您链接的示例代码专门检查
    FILE\u ATTRIBUTE\u repasse\u POINT
    。这不会检测到连接。它检测所有重分析点。连接只是重分析点的一个示例。在Windows中,连接点作为重分析点实现。要区分不同类型的重分析点,必须使用
    DeviceIoControl(FSCTL\u GET\u repasse\u POINT)
    。返回的
    reparseu DATA\u BUFFER
    struct有一个
    ReparseTag
    字段(对于连接点,它被设置为
    IO\u reparseu TAG\u MOUNT\u POINT
    )。您可以保存对
    文件的需要。ISSYMBOLICLINK(路径)
    通过反射性地检查
    WindowsFileAttributes
    parseTag
    字段,一个连接的值将为-1610612733(和一个符号链接-1610612724),只需将
    try
    块中的内容替换为:
    field field=attr.getClass().getDeclaredField(“reparseTag”);字段。setAccessible(true);int parseTag=(int)field.get(attr);布尔值isJunction=parseTag==-1610612733它似乎不起作用。toRealPath()与连接的路径本身相同。这是连接上所期望的。所以这段代码不起作用,是吗?对于连接点,p.compareTo(p.toRealPath())是0,正如您同意的和我在测试中看到的一样。@Peter为什么会这样?尽管有流行的观点,交叉点并不是硬连接。NTFS有硬链接、连接和符号链接。符号链接和连接之间的区别在于遍历UNC目标,而这些目标的连接做得不好。我更新了上面提到的要点,还包括了一个硬链接示例(仅在文件中可能)。因此,可以通过Files.isRegularFile()来区分这些文件。但上述方法对交叉口效果良好。你能给我一个例子,你所说的穿越UNC目标是什么意思。解决方案的可能来源: