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

时间:2012-12-05 22:02:43

标签: java windows winapi jna

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

我尝试的第一件事是:

Files.isSymbolicLink(aPath)

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

还尝试了这里提出的解决方案(使用JNA库): Stackoverflow question (3249117) ,但它从未在我知道的任何文件中返回true。

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

DIR /S /A:L

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

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

4 个答案:

答案 0 :(得分:7)

如果你有正确的java,比如Oracle jdk 8,可以有一种方法可以做到这一点。它很狡猾,它可以停止工作,但是....

您可以获得与链接相关的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)

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

答案 1 :(得分: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 Hard Links, Directory Junctions, and Windows Shortcuts

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

答案 2 :(得分:5)

使用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;
}

答案 3 :(得分:1)

在Windows上,联结的属性包含isSymbolicLink() == false,但他们有isOther() == true。所以你可以这样做:

boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
BasicFileAttributes attrs = Files.readAttributes(aPath, BasicFileAttributes.class);
boolean isJunction = isWindows && attrs.isDirectory() && attrs.isOther();