如何在Java中创建一个新的zip文件并向其中添加一个大的文件目录?

如何在Java中创建一个新的zip文件并向其中添加一个大的文件目录?,java,filesystems,zip,zipfile,Java,Filesystems,Zip,Zipfile,我正在尝试将文件目录添加到zip。目录大约有150个文件大。在一些5-75个文件中,我不断收到一个崩溃消息,错误消息是“该进程无法访问该文件,因为它正被另一个进程使用。” 我尝试了一个延迟,这可能会有所帮助,但肯定不能解决错误 使用以下来源的代码: final File folder=新文件(“C:/myDir/img”); 对于(最终文件条目:folder.listFiles()){ if(fileEntry.isDirectory()){ 继续; } 否则{ 字符串文件名=fileEntr

我正在尝试将文件目录添加到zip。目录大约有150个文件大。在一些5-75个文件中,我不断收到一个崩溃消息,错误消息是“该进程无法访问该文件,因为它正被另一个进程使用。”

我尝试了一个延迟,这可能会有所帮助,但肯定不能解决错误

使用以下来源的代码:

final File folder=新文件(“C:/myDir/img”);
对于(最终文件条目:folder.listFiles()){
if(fileEntry.isDirectory()){
继续;
}
否则{
字符串文件名=fileEntry.getName();
字符串tobeadedname=“C:/myDir/img/”+文件名;
Path tobeaded=FileSystems.getDefault().getPath(tobeadedname.toabsolutionPath();
createZip(zipLocation,tobeaded,“./”+文件名);
System.out.println(“添加的文件”+++计数);
//延迟是因为“文件正在使用”错误
试试{Thread.sleep(1000);}//1secs
捕获(中断异常e){}
}
}
公共静态void createZip(路径zipLocation、路径tobeaded、字符串internalPath)抛出Throwable{
Map env=new HashMap();
//检查文件是否存在。
put(“create”,String.valueOf(Files.notExists(zipLocation));
//使用zip文件系统URI
URI fileUri=zipLocation.toUri();//此处
URI zipUri=新URI(“jar:+fileUri.getScheme(),fileUri.getPath(),null);
系统输出打印(zipUri);
//URI=URI.create(“jar:file:+zipLocation);//这里创建zip
//试用资源
try(FileSystem-zipfs=FileSystems.newFileSystem(zipUri,env)){
//在zipfs中创建内部路径
Path internalTargetPath=zipfs.getPath(internalPath);
//创建父目录
Files.createDirectories(internalTargetPath.getParent());
//将文件复制到zip文件中
复制(toheaded、internalTargetPath、StandardCopyOption.REPLACE_EXISTING);
}
}

我不能保证这就是问题的原因,但是您的代码以一种奇怪的方式将文件压缩成ZIP文件,或者至少是效率低下的方式。具体来说,您要为每个要压缩的文件打开一个新的
文件系统。我假设你是这样做的,因为你链接的Q&A就是这样做的。但是,仅压缩一个文件,而您希望同时压缩多个文件。在压缩目录的整个过程中,您应该保持文件系统
处于打开状态

public static void compress(Path directory, int depth, Path zipArchiveFile) throws IOException {
    var uri = URI.create("jar:" + zipArchiveFile.toUri());
    var env = Map.of("create", Boolean.toString(Files.notExists(zipArchiveFile, NOFOLLOW_LINKS)));

    try (var fs = FileSystems.newFileSystem(uri, env)) {
        Files.walkFileTree(directory, Set.of(), depth, new SimpleFileVisitor<>() {

            private final Path archiveRoot = fs.getRootDirectories().iterator().next();

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                // Don't include the directory itself
                if (!directory.equals(dir)) {
                    Files.createDirectory(resolveDestination(dir));
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.copy(file, resolveDestination(file), REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }

            private Path resolveDestination(Path path) {
                /*
                 * Use Path#resolve(String) instead of Path#resolve(Path). I couldn't find where the
                 * documentation mentions this, but at least three implementations will throw a 
                 * ProviderMismatchException if #resolve(Path) is invoked with a Path argument that 
                 * belongs to a different provider (i.e. if the implementation types don't match).
                 *
                 * Note: Those three implementations, at least in OpenJDK 12.0.1, are the JRT, ZIP/JAR,
                 * and Windows file system providers (I don't have access to Linux's or Mac's provider
                 * source currently).
                 */
                return archiveRoot.resolve(directory.relativize(path).toString());
            }

        });
    }
}
publicstaticvoidcompress(路径目录、int深度、路径zipArchiveFile)引发IOException{
var uri=uri.create(“jar:+zipArchiveFile.toUri());
var env=Map.of(“create”,Boolean.toString(Files.notExists(zipArchiveFile,NOFOLLOW_LINKS));
try(var fs=FileSystems.newFileSystem(uri,env)){
Files.walkFileTree(目录,Set.of(),深度,新的SimpleFileVisitor()){
私有最终路径archiveRoot=fs.getRootDirectories().iterator().next();
@凌驾
公共文件VisitResult preVisitDirectory(路径目录,基本文件属性属性属性)引发IOException{
//不要包含目录本身
如果(!directory.equals(dir)){
createDirectory(resolveDestination(dir));
}
返回FileVisitResult.CONTINUE;
}
@凌驾
公共文件VisitResult visitFile(路径文件,基本文件属性属性属性)引发IOException{
复制(文件、解析目标(文件)、替换现有文件);
返回FileVisitResult.CONTINUE;
}
专用路径解析目标(路径路径){
/*
*使用Path#resolve(String)而不是Path#resolve(Path)。我找不到
*文档中提到了这一点,但至少有三个实现会抛出错误
*如果使用以下路径参数调用#resolve(Path),则ProviderMismatchException
*属于不同的提供程序(即,如果实现类型不匹配)。
*
*注意:至少在OpenJDK 12.0.1中,这三种实现是JRT、ZIP/JAR、,
*和Windows文件系统提供商(我没有访问Linux或Mac的提供商的权限)
*来源(当前)。
*/
返回archiveRoot.resolve(directory.relativize(path.toString());
}
});
}
}
注意:使用
depth
参数的方式与中的
maxDepth
完全相同

注意:如果您只关心目录本身中的文件(即不希望递归遍历文件树),则可以使用。完成后不要忘记关闭


您反复打开和关闭
文件系统可能会导致您的问题,在这种情况下,上述操作应该可以解决问题。

我不能保证这是您的问题的原因,但您的代码会以一种奇怪的方式将文件压缩成ZIP文件,或者至少效率低下。具体来说,您要为每个要压缩的文件打开一个新的
文件系统。我假设你是这样做的,因为你链接的Q&A就是这样做的。但是,仅压缩一个文件,而您希望同时压缩多个文件。在压缩目录的整个过程中,您应该保持文件系统
处于打开状态

public static void compress(Path directory, int depth, Path zipArchiveFile) throws IOException {
    var uri = URI.create("jar:" + zipArchiveFile.toUri());
    var env = Map.of("create", Boolean.toString(Files.notExists(zipArchiveFile, NOFOLLOW_LINKS)));

    try (var fs = FileSystems.newFileSystem(uri, env)) {
        Files.walkFileTree(directory, Set.of(), depth, new SimpleFileVisitor<>() {

            private final Path archiveRoot = fs.getRootDirectories().iterator().next();

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                // Don't include the directory itself
                if (!directory.equals(dir)) {
                    Files.createDirectory(resolveDestination(dir));
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.copy(file, resolveDestination(file), REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }

            private Path resolveDestination(Path path) {
                /*
                 * Use Path#resolve(String) instead of Path#resolve(Path). I couldn't find where the
                 * documentation mentions this, but at least three implementations will throw a 
                 * ProviderMismatchException if #resolve(Path) is invoked with a Path argument that 
                 * belongs to a different provider (i.e. if the implementation types don't match).
                 *
                 * Note: Those three implementations, at least in OpenJDK 12.0.1, are the JRT, ZIP/JAR,
                 * and Windows file system providers (I don't have access to Linux's or Mac's provider
                 * source currently).
                 */
                return archiveRoot.resolve(directory.relativize(path).toString());
            }

        });
    }
}
publicstaticvoidcompress(路径目录、int深度、路径zipArchiveFile)引发IOException{
var uri=uri.create(“jar:+zipArchiveFile.toUri());
var env=Map.of(“create”,Boolean.toString(Files.notExists(zipArchiveFile,NOFOLLOW_LINKS));
try(var fs=FileSystems.newFileSystem(uri,env)){
Files.walkFile