如何替换jar文件中某个目录中的某些文件?
Posted
技术标签:
【中文标题】如何替换jar文件中某个目录中的某些文件?【英文标题】:how to replacing some files within a certain directory inside a jar file? 【发布时间】:2014-10-02 07:11:11 【问题描述】:我在替换或更新 jar 文件中某个目录中的某些文件时遇到问题。
我已经阅读了一些帖子。此链接上给出的代码(JarUpdater 类)Updating .JAR's contents from code
对我理解ZipInputStream、ZipOutputStream和ZipEntry等的作用和使用非常有帮助。
但是,当我运行它时,
-
我有一个 EOF 异常
[由 mk7 编辑:经过 20 次左右,我发现 jar 文件已损坏。因此,在我将 jar 文件替换为新文件后,EOF 异常就消失了。下面的另外两个问题仍未解决]
这两个新的 xml 文件只会被复制到 jar 文件的“根目录”。
这两个新的 xml 文件永远不会替换名为 /conf 的目录中的两个原始文件。
为了将 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();
【问题讨论】:
【参考方案1】:在您复制不想替换的条目的第一个周期(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();
此外,当您检查是否要替换条目时,您应该将其与完整路径进行比较,而不仅仅是与文件名进行比较。例如,如果要替换 /conf
文件夹中的 abc.xml
,则应将条目名称与 "/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()));
【讨论】:
我只是仔细检查。代码确实有 out.closeEntry();和 in.close(); 这是损坏的 jar 文件。所以在我替换了jar文件后,EOF异常就消失了。我编辑了我原来的问题并删除了我第一次遇到的 EOF 异常问题。但即使是现在,我仍然没有替换这两个文件。 添加了正确检查是否要替换条目的代码(您没有正确检查,因此您没有过滤掉要替换的条目)。 你是对的。我对完整路径不小心。现在效果很好。非常感谢!【参考方案2】:对于协议为 jar:file:
(可用于所有 zip 文件)的 URI,您可以使用 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 的一种方法是将“jar:”添加到 File.toURI()
的前缀。
这更加优雅和抽象,并且还允许 Files.copy 进出 zip。工具箱里可以放一些东西。
【讨论】:
太好了。我看过一些关于使用 File.toURI() 的帖子。我还不完全理解它如何以及为什么使用这种方法。我可以列出完整的代码以便从头到尾查看吗?非常感谢! 完成,File.toURI()
前置“file:/”,将 Windows ` into '/' and replaces spaces to
%20. Java has a built-in protocol handler for
jar:` 转换为任何 zip 格式。以上是关于如何替换jar文件中某个目录中的某些文件?的主要内容,如果未能解决你的问题,请参考以下文章