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目标是什么意思。解决方案的可能来源: