Java 在Windows文件系统上处理unix符号链接文件

Java 在Windows文件系统上处理unix符号链接文件,java,windows,macos,symlink,zipfile,Java,Windows,Macos,Symlink,Zipfile,我目前正在从事一个Java项目,该项目应允许用户导出与Windows软件(.exe)或OS X应用程序(.app)捆绑的项目,以便将数据分发到其他工作站。Windows和OS X软件都存储为压缩的zip文件,并在导出项目时解压缩。我的问题是,在Windows上解压OSX应用程序会破坏捆绑框架内的符号链接。这反过来会破坏应用程序的签名,并在应用程序在OS X上启动时引发问题 我使用ApacheCommons压缩库来解压缩包,这使我能够检测符号链接及其目标。使用OS X,我可以使用java.nio.

我目前正在从事一个Java项目,该项目应允许用户导出与Windows软件(.exe)或OS X应用程序(.app)捆绑的项目,以便将数据分发到其他工作站。Windows和OS X软件都存储为压缩的zip文件,并在导出项目时解压缩。我的问题是,在Windows上解压OSX应用程序会破坏捆绑框架内的符号链接。这反过来会破坏应用程序的签名,并在应用程序在OS X上启动时引发问题

我使用ApacheCommons压缩库来解压缩包,这使我能够检测符号链接及其目标。使用OS X,我可以使用java.nio.file.Files中的方法重新创建符号链接,但在Windows中,这需要管理员权限,我有点犹豫是否将其添加为使用该软件的先决条件(即使启用,我也不相信这会起作用-还没有尝试)

我对链接断开的原因有一点了解,但如果我理解正确,Windows文件系统不支持Unix符号链接的文件类型,因此链接被解压缩为普通文件,在OS X上打开时将不再被识别为符号链接

所以,我的问题是,我是否可以以某种方式将符号链接文件按位复制到Windows文件系统,以保留Unix特定的位,还是完全不可能保留这些信息?或者我应该改变导出方法,将项目文件添加到现有的zip文件中,在这种情况下,符号链接信息可能会被保留,直到在目标机器上提取zip为止

ZipFile
的每个
ZipArchiveEntry
上循环的当前代码如下:

byte data[] = new byte[BUFFER];

Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();

while (entries.hasMoreElements()) {
    ZipArchiveEntry zipEntry = entries.nextElement();
    String destFilename = copyFolder + zipEntry.getName();
    File destFile = new File(destFilename);

    if (zipEntry.isUnixSymlink()) {             
        File target = new File(zipFile.getUnixSymlink(zipEntry));              
        try {   
            // Try to create symbolic link - currently only works with OS X
            Files.createSymbolicLink(destFile.toPath(), target.toPath());
            continue;
        } catch (Exception e) {
            System.out.println("Failed to create symbolic link: " + 
                destFile.getAbsolutePath() + " -> " + 
                target.getAbsolutePath());
        }
    }

    // If file
    int count;
    FileOutputStream fos = new FileOutputStream(destFile);

    try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER)) {
        InputStream is = zipFile.getInputStream(zipEntry);
        while ( (count = is.read(data, 0, BUFFER)) != -1) {
            dest.write(data, 0, count);
        }
    }
}
byte data[]=新字节[缓冲区];
枚举条目=zipFile.getEntries();
while(entries.hasMoreElements()){
ZipArchiveEntry zipEntry=entries.nextElement();
字符串destFilename=copyFolder+zipEntry.getName();
文件destFile=新文件(destFilename);
如果(zipEntry.isUnixSymlink()){
文件目标=新文件(zipFile.getUnixSymlink(zipEntry));
试试{
//尝试创建符号链接-目前仅适用于OS X
createSymbolicLink(destFile.toPath(),target.toPath());
继续;
}捕获(例外e){
System.out.println(“未能创建符号链接:”+
destFile.getAbsolutePath()+“->”+
target.getAbsolutePath());
}
}
//如果文件
整数计数;
FileOutputStream fos=新的FileOutputStream(destFile);
try(BufferedOutputStream dest=新的BufferedOutputStream(fos,缓冲区)){
InputStream is=zipFile.getInputStream(zipEntry);
而((计数=is.read(数据,0,缓冲区))!=-1){
目的写入(数据,0,计数);
}
}
}

Windows文件系统使用与UNIX类似的方法来定义符号链接(如硬链接或软链接),但它们不是100%兼容的。您可以在此处阅读更多有关内容: 这个问题的简单答案是:不能只按位复制链接,使其具有相同的Unix特定位,因为Windows NTFS没有这些位。JAVA也被设计为在沙箱中工作,所以您没有访问系统底层API的权限来“随心所欲”。我不会用JAVA来完成这种特定于系统的任务。也许你不必这么做


根据您在此项目中的角色,您可以重新定义捆绑包应该包含的内容。你真的需要里面的符号链接吗?也许更普遍的做法是使用某种“属性”文件将不同部分映射到一起?还是将其作为数据库分发?尽量不要依赖于系统特定的实现

您需要一种特定于Windows的“非标准”(至少对于Java)方法来解决这个问题,因为没有一种标准的跨平台Java方法来解决这个问题。例如,您可以尝试在调用的同时使用
Runtime.exec
。“mklink”命令允许创建硬链接和软(符号)链接,还允许创建连接——基本上它创建了Windows文件系统可用的各种类型的重新解析点。如果您愿意访问本机代码,那么您也可以使用预先制作的or并调用提供的
WinBase.h
方法。

一般来说,我建议您尽可能避免在Windows上使用符号链接和硬链接

符号链接和硬链接很晚才引入Windows,对它的支持相当差:

  • 大多数Windows用户不希望在其文件系统中使用符号链接
  • 符号链接仅在NTFS文件系统上本地受支持,而在其他文件系统(FAT、exFAT、UDF)上或通过网络共享不受支持
  • 第三方工具(拉链、备份工具、云同步软件)和一些Microsoft软件(例如文件版本历史记录,即Windows的“时间机器”;或复制/移动文件夹时的Windows资源管理器)无法处理符号链接或硬链接,或者解决它们,或者崩溃/显示错误消息)
  • 创建它们所需的权限因Windows版本而异(在Windows 7上,普通用户可以创建指向他可以访问的目录的符号链接(连接),但在Windows XP上,您在任何情况下都需要管理员权限)

因此,由于您只需要暂时使用符号链接(如您在评论中所写),然后再次压缩文件,我建议在解压缩时创建自己的标记文件来表示符号链接,以后压缩时,您会将它们转换回ZIP文件中正确的UNIX符号链接。

我相信在这种情况下,不是由我来决定捆绑包是否应该包含符号链接——这是苹果使用捆绑框架的方式。不过,感谢您的帮助性回答!:)属性文件是一个好主意,如果您想保留