簡體   English   中英

當使用 zip 文件作為文件系統時,zip 文件未更新

[英]when using a zip file as a FileSystem the zip file is not being update

我想使用標准的 nio 文件和路徑方法來操作 jar。 因此,Java 有辦法通過創建 zip 文件系統來做到這一點:

    try {
        zipFS = FileSystems.newFileSystem(zipDisk, zipFSproperties);
    } catch(Exception e) {
        System.out.println(e.getMessage());
    }

我的測試程序使用現有的 jar 文件作為文件系統,它列出了 jar 中包含的條目。一切都很好。 然后我將一個新文件復制到 jar 並再次列出條目。 正如您所期望的,列表現在包含新添加的文件。 問題是程序關閉后,我打開了 jar 文件系統所基於的 jar 文件,但它沒有添加新條目。 這就是我的問題。 當我添加一個新條目時,jar 文件本身不應該被更改嗎? 我不知道我可以發出的任何命令會導致 zip 文件系統更新為 zip 文件系統包裝的實際 jar 文件; 我在讀更多的文件系統嗎? 是 zip 文件系統中的更改假設導致相應的后端 zip 文件被更新。

代碼:公共 class 主 {

public static void main(String[] args) throws IOException {
    ZipFileSystem zipFS = new ZipFileSystem("C:\\Temp\\mylibrary\\build\\outputs\\jar\\temp\\mylibrary-debug.zip");
    Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().iterator().next().getRoot(),10, (path, basicFileAttributes) -> {
        return !Files.isDirectory(path);
    });
    paths.forEach( path ->
            System.out.println ("zip contains entry: " + path)
    );

    File file = new File("C:\\Temp\\mylibrary\\src\\main\\java\\com\\phinneyridge\\android\\myLib.java");
    System.out.println("copying " + file.getPath());
    Path outPath = zipFS.zipFS.getPath("myLib.java");
    Files.copy (file.toPath(), outPath, StandardCopyOption.REPLACE_EXISTING);
    paths = Files.find(zipFS.zipFS.getPath(""),10, (path, basicFileAttributes) -> {
        return !Files.isDirectory(path);
    });
    paths.forEach( path ->
            System.out.println ("zip contains entry: " + path)
    );
}

}

我添加的代碼顯示我訪問一個 zip 文件,列出它包含的當前條目,添加一個新條目(通過文件復制),最后再次列出內容。 所有這些代碼都可以正常工作。 不起作用的是當應用程序結束時,對 zip 文件系統的更改不會合並回 zip 文件。 我很驚訝 zip 文件沒有得到更新,但我現在認為它正在按預期工作; 沒有做我想讓它做的事,但沒關系。 我找不到任何文檔說它會更新文件系統 object 源自的 jar 文件。 所以我基本上問的是正確的行為,還是我完全缺少導致 zip 文件系統 object 更新 Zip 文件的東西?

這是我嘗試 Dunc 建議時的代碼: public static void main(String[] args) throws IOException {

    ZipFileSystem zipFS = new ZipFileSystem("C:\\Temp\\mylibrary\\build\\outputs\\jar\\temp\\mylibrary-debug.zip");
    try (FileSystem fs = zipFS.zipFS) {
        try (Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().
                iterator().next().getRoot(), 10, (path, basicFileAttributes) -> {
            return !Files.isDirectory(path);
        })) {
            paths.forEach(path ->
                    System.out.println("zip contains entry: " + path)
            );
        }

        File file = new File("C:\\Temp\\mylibrary\\src\\main\\java\\com\\phinneyridge\\android\\myLib.java");
        System.out.println("copying " + file.getPath());
        Path outPath = fs.getPath("myLib.java");
        Files.copy(file.toPath(), outPath, StandardCopyOption.REPLACE_EXISTING);

        try (Stream<Path> paths = Files.find(zipFS.zipFS.getRootDirectories().
                iterator().next().getRoot(), 10, (path, basicFileAttributes) -> {
            return !Files.isDirectory(path);
        })) {
            paths.forEach(path ->
                    System.out.println("zip contains entry: " + path)
            );
        }
    } catch (Exception e) {
        System.out.println("FileSystem Error: " + e.getClass().getName() + " - " + e.getMessage());
        e.printStackTrace();
    }
}

}

順便說一句,ZipFileSystem 是文件系統的包裝器 class。 我也會發布該代碼,以防那是我做錯事的地方。

public class ZipFileSystem {
FileSystem zipFS;
Path zipFSPath;

/**
 * Constructor for a ZipFile object
 * @param zipFilePath string representing the path to the zipfile.  If the path doesn't exist,
 * the zip file will be automatically created.  If the path exist, it must be a file (not
 * a directory) and it must be a valid zip file
 */
public ZipFileSystem(String zipFilePath) {
    Map<String, String> zipFSproperties = new HashMap<>();
    /* set create to true if you want to create a new ZIP file */
    zipFSproperties.put("create", "true");
    /* specify encoding to UTF-8 */
    zipFSproperties.put("encoding", "UTF-8");
    /* Locate File on disk for creation */
    URI zipFileUri = new File(zipFilePath).toURI();
    URI zipDisk = URI.create("jar:" + zipFileUri);
    zipFSPath = Paths.get(zipFileUri);
    if (!Files.exists(zipFSPath)) {
        try {
            createEmptyZipFile(zipFSPath);
        } catch (Exception e ) {
            System.out.println(e.getMessage());
        }
    } else {
        if (Files.isDirectory(zipFSPath)) {
        } else {
            try {
                // let's open it, which will verify if it's a valid zip file
                ZipFile zipFile = new ZipFile(zipFilePath);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
    try {
        zipFS = FileSystems.newFileSystem(zipDisk, zipFSproperties);
    } catch(Exception e) {
        System.out.println(e.getMessage());
    }
    try {
        listFiles(zipFS.getPath("/"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Path打開 zip 的正確方法 - 如果不存在則創建 - 是:

Path zip = Path.of("/Somepath/to/xyz.zip");
Map<String, String> env = Map.of(
    "create", "true"
    // other args here ...
);
try (FileSystem fs = FileSystems.newFileSystem(zip, env)) {
     // code to read/update here
}

您沒有正確關閉任何文件或流,因此您的更改可能不會刷新回文件系統,並且會保留阻止某些操作的文件句柄。

對將管理對 zip 文件系統的修改以及從Files.find關閉每個Stream<Path>的每個操作使用 try with resources,並檢查其他地方(例如createEmptyZipFile )是否存在相同問題:

try (FileSystem fs = ... ) {

    try (Stream<Path> paths = Files.find(...) ) {
    }
    
    Files.copy( ... );

    try (Stream<Path> paths = Files.find(...) ) {
    }
}

該進程無法訪問該文件,因為它正被另一個進程使用

您有不必要的代碼ZipFile zipFile = new ZipFile(zipFilePath)測試 zip 是否有效並且您不調用close() ,因此它將阻止 zip 更改被寫回。 可以安全地刪除該檢查(就像FileSystems.newFileSystem一樣)或者必須將其包裝在try() {}中,以便在您對zipFile文件系統進行編輯之前關閉 zipFile。

暫無
暫無

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

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