簡體   English   中英

Java將文件復制到zip中AccessDeniedException

[英]Java Copy files into zip AccessDeniedException

說明:

我已經用Java 8創建了一個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();
    }

問題:

每當我添加行Files.copy將目錄以及所有子目錄和子文件復制到zip文件時,我都會收到以下異常: java.nio.file.AccessDeniedException: .\\backups\\test.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方法時,甚至都不會創建ZIP文件或至少沒有保存ZIP文件,因此,在為我嘗試復制的每個目錄和文件拋出AccessDeniedException之后,將引發NoSuchFileException

我從未使用過java.nio.file,但是一旦我不得不處理此類任務,便使用了java.util.zip,它非常簡單,僅用於從目錄創建zip文件。

雖然,如果您無法更改用於歸檔目錄的內容,那么該解決方案將無濟於事,但示例代碼帶有一些解釋:

  • 使用新的ZipOutputStream創建新的ZIP存檔
  • 遍歷將要用Files.walk壓縮的文件樹
  • 對於文件樹的每個路徑,打包條目。 ZipEntry在存檔中保存有關單個文件的元數據

要使用它,只需調用帶有src路徑和destination.zip的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();
}

您正在嘗試使用常規文件作為目錄。

在這條線

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另一個文件系統的,所以你就必須解決像目標路徑

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
}

如果目標目錄存在源也是目錄,則將跳過路徑條目,因為應通過異常報告源不是目錄但目標是現有目錄的情況。

如果要強制執行替換現有文件和目錄的策略,則在存在現有非空目錄的情況下,必須執行樹刪除操作,但是仍然必須跳過根目錄,而不能被刪除。

不久前,我發布了一些實用程序類,用於使用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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM