[英]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.