当前位置: 首页 > 知识库问答 >
问题:

Java复制文件到zip AccessDeniedException

巩镜
2023-03-14

我在Java8中创建了一个ZIP文件,并尝试将包含所有子文件和目录的目录复制到这个zip文件中。

   Path directory = Paths.get("P:\Java\Test\backups\test.zip");
   // path to the world;
   Path world = Paths.get("P:\Java\Test\world");
   
   [...]
   
    // Create a map which tells the file system to create a new file if it doesn't exist
    ImmutableMap immutableMap = ImmutableMap.of("create", String.valueOf(Files.notExists(this.directory)));
    
    // Get a file system provider which is capable of creating a ZIP file
    FileSystemProvider zipProvider = FileSystemProvider.installedProviders().stream()
            .filter(provider -> provider.getScheme().equals("jar")).findFirst().get();
    
    // Create the file system
    try (FileSystem fs = zipProvider.newFileSystem(this.directory, immutableMap)) {
        
        try {
            Files.walk(this.world).forEach((Path sourcePath) -> {
                try {
                CopyOption[] option = new CopyOption[] {
                        StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES
                };
                Path destination = this.directory.resolve(this.world.relativize(sourcePath));
                Files.copy(sourcePath, destination,option);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

每当我添加行文件时。复制要将我的目录以及所有子目录和子文件复制到zip文件中,我遇到了以下异常:java。nio。文件AccessDeniedException:。\备份\测试。邮政编码

在下面的stacktrace中,我将类调用的行号更改为我在上面发布的代码段的行号,以提高可读性,但对ThreadBackup的调用除外。运行方法。它基本上是代码与其他一些不相关的东西一起执行的方法。

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)

我注意到每当我调用文件时。copy方法ZIP文件甚至没有创建或至少没有保存,因此在我尝试复制的每个目录和文件抛出AccessDeniedException之后,就会抛出NoSuchFileException。


共有3个答案

越胤
2023-03-14

不久前,我发布了一些实用程序类,用于使用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来解析跨文件系统的路径。

有一个教程。

该库是开源的,可从Maven Central获得:

<dependency>
    <groupId>org.softsmithy.lib</groupId>
    <artifactId>softsmithy-lib-core</artifactId>
    <version>0.9</version>
</dependency>
鞠通
2023-03-14

您正在尝试使用常规文件作为目录。

在这一行

try (FileSystem fs = zipProvider.newFileSystem(this.directory, immutableMap)) {

您正在此处打开或创建zip文件系统。目录,它必须是默认文件系统中的有效路径。成功后,this。目录肯定是一个常规文件(zip文件格式),仍然在默认文件系统中。

这条线

Path destination = this.directory.resolve(this.world.relativize(sourcePath));

将此常规文件视为目录。

您想复制到zip文件系统中,因此您必须使用zip文件系统中的路径,而不是默认文件系统中zip文件的路径。

您可以获得zip文件系统的根,例如。

Path zipRoot = fs.getPath("/");

并将其用作目标。据我所知,您不能使用从一个文件系统检索到的Path作为另一个文件系统的Path方法的参数,因此您必须解析目标路径,例如

Path destination = zipRoot;
for(Path p: this.world.relativize(sourcePath))
    destination = destination.resolve(p.toString());

但也许有一种更简单的方法。

另一个问题是文件的使用。复制目录。当目录已经存在(并且根目录始终存在)时,它将失败,除非您指定“替换现有目录”,但只要目标目录不为空,它就会失败。这个最简单的解决方案是保持现有目录不变,因此代码如下所示

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
}

如果目标目录存在并且源也是目录,这将跳过路径条目,因为源不是目录但目标是现有目录的情况应通过异常报告。

如果要强制执行替换现有文件和目录的策略,则必须在存在现有非空目录的情况下实现树删除,但仍然必须跳过无法删除的根目录。

公冶高峯
2023-03-14

我从未使用过java。nio。文件,但有一次我不得不处理这样的任务,我使用java。util。zip,仅用于从目录创建zip文件就非常简单

尽管如此,如果您无法更改用于归档目录的内容,那么此解决方案将不会有多大帮助,但示例代码中有一些解释:

  • 使用新的ZipOutputStream创建新的ZIP存档
  • 浏览文件树,它将与文件一起压缩。步行
  • 为文件树的每个路径打包条目。ZipEntry保存关于归档中单个文件的元数据

要使用它,只需使用src和目标路径调用方法packDir。拉链

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();
}
 类似资料:
  • 我正在尝试使用Java复制文件。我有一个需要复制的文件对象的arraylist,但是当实际复制发生时,目标文件夹会变成一个文件,不会复制任何东西

  • 这里是Java 8。我有一个S3 bucket(),其文件夹子结构如下: 以下是文件夹的外观: 我有一个软件可以将图像文件上传到文件夹,然后我正在编写的另一个应用程序应该处理该图像并将其复制到文件夹。我必须执行这个S3副本的代码如下: 当它运行时,我看到以下日志输出: 但是文件夹的最终状态如下所示: 因此,它不是将复制到目录,而是直接在下创建一个新文件,并将其命名为,并可能将图像的二进制内容复制到

  • 我想将文件salesjan2009.csv(存储在本地文件系统中,~/input/salesjan2009.csv)复制到HDFS(Hadoop分布式文件系统)主目录中 我编写了这段代码hduser@ubuntu:/usr/local/hadoop$hdfs dfs-copyfromlocal'/home/hduser/desktop/input/salesjan2009.csv'/hdfs-pa

  • 使用Java8。 为了获得最佳性能,我尝试用复制文件,但很快发现它不支持汉字。例如: 代码打算从jar复制一个文件,但它抛出了一个异常(a“我的" 文件夹已提前创建): 问题是鎴戠殑" 甚至连一个中国人都看不懂,所以我正在寻找一个解决办法来处理汉字。 我也尝试了FileChannel,但失败了,意识到它用于直接文件,而不是在一个jar中的文件。我该怎么做?

  • 问题内容: 我有一个pom.xml文件,其中包含以下内容: 里面有一些文件夹,其中不包含任何.java文件。当我开始编译时,它们不会复制到目录中。 仅将.java文件移动(当然是在编译后)并存储在正确的文件夹中。 有人可以在不使用任何插件的情况下帮助我解决此问题吗? 我尝试过 但这行不通。怎么了? 问题答案: 如果它们不是Java文件,则应将它们移至and / or 目录。这是存储非Java文件的

  • rank ▲ ✰ vote url 50 404 65 510 url 复制文件 怎么在Python里赋值文件?在os下没找到复制的方法. shutil有许多的方法.其中之一就是: copyfile(src, dst) 把src文件的内容复制给dst.目的地址必须是可写的;否则将会出现IOError错误.如果dst已经存在,将会被覆盖.一些像字符或者块设备不能用这个方法赋值.src和dst是路径