我在Java 8中创建了一个ZIP文件,并尝试将包含所有子文件和目录的目录复制到此zip文件中。
Files.copy
每当我添加行java.nio.file.AccessDeniedException: .\backups\test.zip
以将我的目录以及所有子目录和子文件复制到zip文件中时,我都会遇到以下异常:ThreadBackup.run
在下面的堆栈跟踪中,我将类调用的行号更改为我在上面发布的代码段中的一行,以便更好地提供可读性,除了调用java.nio.file.AccessDeniedException: .\backups\tests.zip
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileCopy.copy(WindowsFileCopy.java:231)
at sun.nio.fs.WindowsFileSystemProvider.copy(WindowsFileSystemProvider.java:278)
at java.nio.file.Files.copy(Files.java:1274)
at serverutilities.backups.ThreadBackups.lambda$createZipFile$1(ThreadBackups.java:24)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at serverutilities.backups.ThreadBackups.createZipFile(ThreadBackups.java:18)
at serverutilities.backups.ThreadBackups.run(ThreadBackups.java:56)
at java.lang.Thread.run(Thread.java:748)
java.nio.file.NoSuchFileException: P:\Java\Test\backups\test.zip
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:90)
at sun.nio.fs.WindowsLinkSupport.getRealPath(WindowsLinkSupport.java:259)
at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:836)
at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:44)
at com.sun.nio.zipfs.ZipFileSystemProvider.removeFileSystem(ZipFileSystemProvider.java:322)
at com.sun.nio.zipfs.ZipFileSystem.close(ZipFileSystem.java:305)
at serverutilities.backups.ThreadBackups.createZipFile(ThreadBackups.java:32)
at serverutilities.backups.ThreadBackups.run(ThreadBackups.java:56)
at java.lang.Thread.run(Thread.java:748)
方法。它基本上是代码与其他一些但无关的东西执行的方法。
Files.copy
我注意到,每当我调用NoSuchFileException
方法时,ZIP文件甚至都没有创建或者至少没有保存,因此AccessDeniedException
在抛出function Get-Customer {
[CmdletBinding()]
Param(
[string]$CustomerName = "*"
)
Process {
# real process iterate on fodlers.
New-Object PSObject -Property @{
CustomerName = $CustomerName;
}
}
}
function Get-Device {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName)]
[string]$CustomerName = "*",
[string]$DeviceName = "*"
)
Process {
# real process iterate on fodlers.
New-Object PSObject -Property @{
CustomerName=$CustomerName;
DeviceName=$DeviceName
}
}
}
之后抛出我尝试复制的每个目录和文件。
答案 0 :(得分:3)
我从未使用过java.nio.file,但是一旦我不得不处理这样的任务而且我使用了java.util.zip,这非常简单,仅用于从目录创建zip文件
虽然,如果您无法更改用于存档目录的内容,那么此解决方案不会给您带来太多帮助,但示例代码中有一些解释:
要使用它,只需调用方法packDir,路径为src和destination.zip
private static void packDir(Path src, Path dest) throws IOException {
try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(dest));
ZipOutputStream zo = new ZipOutputStream(out);
Stream<Path> dirStream = Files.walk(src)) {
dirStream.filter(p -> !p.equals(src)).forEach(path -> {
try {
packEntry(src, zo, path);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
private static void packEntry(Path src, ZipOutputStream zo, Path path) throws IOException {
String name = src.relativize(path).toString().replace('\\', '/');
boolean isDir = Files.isDirectory(path);
if (isDir) {
name += "/";
}
ZipEntry e = new ZipEntry(name);
zo.putNextEntry(e);
if (!isDir) {
Files.copy(path, zo);
}
zo.closeEntry();
}
答案 1 :(得分:1)
您正在尝试将常规文件用作目录。
在这一行
try (FileSystem fs = zipProvider.newFileSystem(this.directory, immutableMap)) {
您正在this.directory
打开或创建一个zip文件系统,该系统必须是默认文件系统中的有效路径。成功后,this.directory
肯定是常规文件(采用zip文件格式),仍在默认文件系统中。
这一行
Path destination = this.directory.resolve(this.world.relativize(sourcePath));
将此常规文件视为目录。
您想要复制到zip文件系统,因此您必须使用zip文件系统中的路径,而不是默认文件系统中zip文件的路径。
您可以获得zip文件系统的根目录,例如
Path zipRoot = fs.getPath("/");
并将其用作目标。据我所知,您不能将从一个文件系统中检索到的Path
用作另一个文件系统的Path
方法的参数,因此您必须解析目标路径,如< / p>
Path destination = zipRoot;
for(Path p: this.world.relativize(sourcePath))
destination = destination.resolve(p.toString());
但也许有一种更简单的方法。
另一个问题是对目录使用Files.copy
。当目录已经存在(并且根目录始终存在)时,它将失败,除非您指定REPLACE_EXISTING
,但是一旦目标目录不为空,这将失败。这个最简单的解决方案是保持现有目录不变,因此代码看起来像
try(FileSystem fs = zipProvider.newFileSystem(this.directory, immutableMap)) {
Path zipRoot = fs.getPath("/");
CopyOption[] option = {
StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES
};
Files.walk(this.world).forEach(sourcePath -> {
try {
Path destination = zipRoot;
for(Path p: this.world.relativize(sourcePath))
destination = destination.resolve(p.toString());
if(!Files.isDirectory(destination) || !Files.isDirectory(sourcePath))
Files.copy(sourcePath, destination, option);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
});
} catch(IOException|UncheckedIOException e) {
e.printStackTrace(); // TODO replace with actual exception handling
}
这将跳过路径条目,如果目标目录存在且源也是目录,因为源不是目录但目标是现有目录的情况应该通过异常报告
如果要强制执行替换现有文件和目录的策略,则必须在存在非空目录的情况下实现树删除,但仍然必须跳过根目录,无法删除。
答案 2 :(得分:0)
前段时间我发布了一些实用程序类,用于使用NIO.2 File API向/从JAR / ZIP文件添加和解压缩文件。
这是教程中的一个片段:
public void addResource(Path zipPath, Path targetDirPath, Path srcPath, String targetInZipPathString) throws IOException {
Path targetZipPath = copyZipFile(zipPath, targetDirPath);
try (FileSystem jarFS = JarFiles.newJarFileSystem(targetZipPath.toUri())) {
Path targetInZipPath = jarFS.getPath(targetInZipPathString);
// Adds the src directory name to the zip. You can omit this if you just want to copy the contents.
Path finalTargetInZipPath = PathUtils.resolve(targetInZipPath, srcPath.getFileName());
Files.createDirectories(finalTargetInZipPath);
CopyFileVisitor.copy(srcPath, finalTargetInZipPath);
}
}
CopyFileVisitor使用PathUtils来解析跨文件系统的路径。
有tutorial。
图书馆为Open Source,可从Maven Central获取:
<dependency>
<groupId>org.softsmithy.lib</groupId>
<artifactId>softsmithy-lib-core</artifactId>
<version>0.9</version>
</dependency>