我遇到了替换或更新jar文件中某个目录中某些文件的问题。
我已经阅读了一些帖子。此链接Updating .JAR's contents from code
中给出的代码(JarUpdater类)对于理解ZipInputStream,ZipOutputStream和ZipEntry等的角色和用法非常有帮助。
但是,当我运行它时,
[由mk7编辑:我发现jar文件在我经历了20次左右后被破坏了。因此,在用新文件替换jar文件后,EOF异常消失了。下面的其他两个问题仍然没有解决]
这两个新的xml文件只会被复制到jar文件的“根目录”中。
这两个新的xml文件永远不会替换名为/ conf的目录中的两个原始文件。
为了用新的xml文件替换xml文件,我应该更改哪些代码?
使用System.out.println,我确实看到while循环遍历每个目录并按预期比较每个文件。一个新的临时罐也按预期创建了...... 我认为声明“notInFiles = false”会照顾我的需要,但事实并非如此。
如何进入/ conf并仅替换这两个文件而不在jar文件的根目录下留下副本?
我错过了什么?感谢您的任何见解!
以下是该链接的代码。
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class JarUpdater {
public static void main(String[] args) {
File[] contents = {new File("abc.xml"),
new File("def.xml")};
File jarFile = new File("xyz.jar");
try {
updateZipFile(jarFile, contents);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void updateZipFile(File jarFile,
File[] contents) throws IOException {
// get a temp file
File tempFile = File.createTempFile(jarFile.getName(), null);
// delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
System.out.println("tempFile is " + tempFile);
boolean renameOk=jarFile.renameTo(tempFile);
if (!renameOk)
{
throw new RuntimeException("could not rename the file "+jarFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jarFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean notInFiles = true;
for (File f : contents) {
System.out.println("f is " + f);
if (f.getName().equals(name)) {
// that file is already inside the jar file
notInFiles = false;
System.out.println("file already inside the jar file");
break;
}
}
if (notInFiles) {
System.out.println("name is " + name);
System.out.println("entry is " + entry);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the contents
for (int i = 0; i < contents.length; i++) {
InputStream in = new FileInputStream(contents[i]);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(contents[i].getName()));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
tempFile.delete();
}
}
答案 0 :(得分:2)
在您复制不想替换的条目的第一个循环(while
循环)中,不要关闭输出zip文件中的条目。像这样添加out.closeEntry();
:
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
// ADD THIS LINE:
out.closeEntry();
此外,当您检查是否要替换条目时,应将其与完整路径进行比较,而不仅仅是文件名。例如,如果要替换abc.xml
文件夹中的/conf
,则应将条目名称与"/conf/abc.xml"
进行比较,而不是"abc.xml"
。
要正确检查是否要更换某个条目:
String name = entry.getName();
boolean notInFiles = true;
for (File f : contents) {
System.out.println("f is " + f);
if (name.equals("/conf/" + f.getName()) {
// that file is already inside the jar file
notInFiles = false;
System.out.println("file already inside the jar file");
break;
}
}
当您将输入的条目添加到替换文件时,您还必须指定具有完整路径的条目名称,例如"/conf/abc.xml"
而不只是"abc.xml"
,因为它会将"abc.xml"
放在输出zip的根目录中。
要执行此操作,请使用"/conf/"
启动条目名称,如下所示:
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry("/conf/" + contents[i].getName()));
答案 1 :(得分:1)
对于协议为jar:file:
的URI(可用于所有zip文件),您可以使用 zip文件系统。
URI jarUri = new URI("jar:" + jarFile.toURI().toString()); // "jar:file:/C:/../xyz.jar"
Map<String, String> zipProperties = new HashMap<>();
zipProperties.put("encoding", "UTF-8");
try (FileSystem zipFS = FileSystems.newFileSystem(jarUri, zipProperties)) {
for (File file : contents) {
Path updatePath = zipFS.getPath("/" + file.getName());
Files.delete(updatePath);
Files.copy(file.toPath(), updatePath, StandardCopyOption.REPLACE_EXISTING);
}
} // closes.
派生URI的一种方法是在前缀&#34; jar:&#34;到File.toURI()
。
这更优雅和抽象,并且允许Files.copy进出zip。保留在工具柜中的东西。