我正在尝试将文件目录添加到zip中。该目录大约有150个文件。装入了5-75个文件,我不断崩溃,并显示错误消息"The process cannot access the file because it is being used by another process."
我尝试了一段时间,这可能会有所帮助,但肯定不能解决问题。
使用以下代码: Is it possible to create a NEW zip file using the java FileSystem?
final File folder = new File("C:/myDir/img");
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
continue;
}
else {
String filename = fileEntry.getName();
String toBeAddedName = "C:/myDir/img/" + filename;
Path toBeAdded = FileSystems.getDefault().getPath(toBeAddedName).toAbsolutePath();
createZip(zipLocation, toBeAdded, "./" + filename);
System.out.println("Added file " + ++count);
//Delay because 'file in use' bug
try { Thread.sleep(1000); } //1secs
catch (InterruptedException e) {}
}
}
public static void createZip(Path zipLocation, Path toBeAdded, String internalPath) throws Throwable {
Map<String, String> env = new HashMap<String, String>();
//Check if file exists.
env.put("create", String.valueOf(Files.notExists(zipLocation)));
//Use a zip filesystem URI
URI fileUri = zipLocation.toUri(); //Here
URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
System.out.println(zipUri);
//URI uri = URI.create("jar:file:"+zipLocation); //Here creates the zip
//Try with resource
try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {
//Create internal path in the zipfs
Path internalTargetPath = zipfs.getPath(internalPath);
//Create parent dir
Files.createDirectories(internalTargetPath.getParent());
//Copy a file into the zip file
Files.copy(toBeAdded, internalTargetPath, StandardCopyOption.REPLACE_EXISTING);
}
}
答案 0 :(得分:0)
我不能保证这是造成您问题的原因,但是您的代码以一种奇怪的或至少效率低下的方式将文件压缩为ZIP文件。具体来说,您要为每个要压缩的文件打开一个新的FileSystem
。我假设您正在按照这种方式进行操作,因为这就是您链接到的Q&A所做的。但是,that answer仅压缩一个文件,而您想同时压缩多个文件。在压缩目录的整个过程中,应保持FileSystem
处于打开状态。
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());
}
});
}
}
注意::depth
参数的使用方式与Files#walkFileTree
中的maxDepth
完全相同。
注意::如果您只关心目录本身中的文件(即不想递归遍历文件树),则可以使用Files#list(Path)
。完成操作后,别忘了关闭Stream
。
您可能一遍又一遍地打开和关闭FileSystem
会导致问题,在这种情况下,上述内容应该可以解决问题。