我一直在寻找一种方法来确定文件是否是一个交汇点,并且没有找到任何令人满意的答案。
我尝试的第一件事是:
Files.isSymbolicLink(aPath)
它仅检测符号链接,而不检测Windows中称为联结的文件。
还尝试了这里提出的解决方案(使用JNA库): Stackoverflow question (3249117) ,但它从未在我知道的任何文件中返回true。
我发现确定哪些文件是联结的唯一方法是在Windows命令提示符下运行以下命令:
DIR /S /A:L
在我的计算机上,它返回66个文件夹,而Files.isSymbolicLink(aPath)仅返回2个文件夹。 所以我想我可以找到一种方法来利用它,但我认为在遍历文件树时它不会非常有效。
有没有办法使用标准的java库,或者替代JNA?
答案 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
:
使用DeviceIoControl()
和FSCTL_GET_REPARSE_POINT
控制代码获取REPARSE_DATA_BUFFER
结构,作为ReparseTag
字段。您可以在以下文章中看到使用此技术的IsDirectoryJunction()
实现示例:
使用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();