java - 如何替换 jar 文件中某个目录中的某些文件?

标签 java jar zipinputstream zipoutputstream

我在替换或更新 jar 文件中特定目录中的某些文件时遇到问题。

我已经阅读了一些帖子。此链接中给出的代码(JarUpdater 类)Updating .JAR's contents from code

对我理解ZipInputStream、ZipOutputStream、ZipEntry等的作用和使用很有帮助。

但是,当我运行它时,

  1. 我有一个 EOF 异常

[由 mk7 编辑:我在检查 20 次左右后发现 jar 文件已损坏。因此,在我用新文件替换 jar 文件后,EOF 异常消失了。下面另外两个问题还没有解决]

  1. 这两个新的 xml 文件只会被复制到 jar 文件的“根目录”。

  2. 这两个新的 xml 文件永远不会替换/conf 目录中的两个原始文件。

为了用新的 xml 文件替换 xml 文件,我应该更改哪些代码行?

对于 System.out.println,我确实看到 while 循环遍历每个目录并按预期比较每个文件。还按预期创建了一个新的临时 jar ... 我认为语句“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();
}
}

最佳答案

在您复制不想替换的条目的第一个循环(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()));

关于java - 如何替换 jar 文件中某个目录中的某些文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26155918/

相关文章:

Java - 覆盖列表的键处理

java - 使用 Newton-Raphson 方法计算平方根的 While 循环条件

java - Gradle 子项目构建配置

java - 将 java 项目导出为 JAR 并尝试在 ECLIPSE 的动态 Web 项目中使用它后,找不到资源文件

jar - 如何在 Golang 中使用 Jar 文件?

java - 如何使用 "is"方法

java - FileNotFoundException 加载 jar 文件,即使该文件已存在

Java 输入流读取缓冲区

java - 机器人 : Zip Folder is invalid

java - 使用 ZipOutputStream 创建的 .war 文件无法部署