文章目录
原始需求
有网友提问: 我想在程序中动态地向同一个jar包中添加文件,比如,我的可执行jar包是test.jar,我要在它运行时生成一些xml文件并将这些文件添加到test.jar中,请问如何实现?
分析
test.jar在运行过程中是无法改变自身内容的,但是可以创建内容与test.jar一致的test2.jar
问题就转换成了:
- 如何复制已有的test.jar重命名为test2.jar
- 如何继续向test2.jar添加新的文件
实施步骤
引入依赖
xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.23.0</version>
</dependency>
核心编码
借助 commons-compress 来操作Jar
java
public void test()
throws IOException
{
String src = getClass().getResource("/apache-jstl.jar").getPath();
String add1 = getClass().getResource("/servlet-api.jar").getPath();
String add2 = getClass().getResource("/log4j2.xml").getPath();
String newJar = src.replace(".jar", DateFormatUtils.format(System.currentTimeMillis(), "_HHmmssSSS") + ".jar");
log.info("源文件: {}", src);
log.info("++新增: {}", add1);
log.info("++新增: {}", add2);
log.info("新文件: {}", newJar);
try (ArchiveOutputStream outputStream = new JarArchiveOutputStream(new FileOutputStream(newJar));
JarArchiveInputStream jarInput = new JarArchiveInputStream(new FileInputStream(src)))
{
JarArchiveEntry jarEntry;
while ((jarEntry = jarInput.getNextJarEntry()) != null)
{
if (!jarEntry.isDirectory())
{
outputStream.putArchiveEntry(jarEntry);
IOUtils.copy(jarInput, outputStream);
}
}
outputStream.flush();
// 追加addFiles
File[] addFiles = {new File(add1), new File(add2)};
for (File addFile : addFiles)
{
JarArchiveEntry addEntry = new JarArchiveEntry("add/" + addFile.getName());
outputStream.putArchiveEntry(addEntry);
try (InputStream entryInputStream = new FileInputStream(addFile))
{
IOUtils.copy(entryInputStream, outputStream);
}
}
// 追加add/001.txt
JarArchiveEntry entry = new JarArchiveEntry("add/001.txt");
outputStream.putArchiveEntry(entry);
outputStream.write("org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;".getBytes(StandardCharsets.UTF_8));
outputStream.closeArchiveEntry();
outputStream.finish();
}
}
使用JDK API实现
java
public void test2()
{
try
{
String src = getClass().getResource("/apache-jstl.jar").getPath();
String add1 = getClass().getResource("/servlet-api.jar").getPath();
String add2 = getClass().getResource("/log4j2.xml").getPath();
String newJar = src.replace(".jar", DateFormatUtils.format(System.currentTimeMillis(), "_HHmmssSSS") + ".jar");
log.info("源文件: {}", src);
log.info("++新增: {}", add1);
log.info("++新增: {}", add2);
log.info("新文件: {}", newJar);
addFilesToJar(new File(src), newJar, new File(add1), new File(add2));
}
catch (IOException e)
{
log.error(e.getMessage(), e);
}
}
/**
* JDK-API实现-将addFiles添加到srcJar并重命名为newJar
*
* @param srcJar
* @param newJar
* @param addFiles
* @throws IOException
*/
private void addFilesToJar(File srcJar, String newJar, File... addFiles)
throws IOException
{
try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(newJar)); JarFile jarFile = new JarFile(srcJar))
{
// 遍历jar文件数据写入新jar
Enumeration<JarEntry> entrys = jarFile.entries();
while (entrys.hasMoreElements())
{
JarEntry jarEntry = entrys.nextElement();
if (!jarEntry.isDirectory())
{
jarOutputStream.putNextEntry(jarEntry);
try (InputStream entryInputStream = jarFile.getInputStream(jarEntry))
{
IOUtils.copy(entryInputStream, jarOutputStream);
}
}
}
// 追加写入
for (File addFile : addFiles)
{
JarEntry jarEntry = new JarEntry("add/" + addFile.getName());
jarOutputStream.putNextEntry(jarEntry);
try (InputStream entryInputStream = new FileInputStream(addFile))
{
IOUtils.copy(entryInputStream, jarOutputStream);
}
}
}
}
运行效果
原始文件
运行后:
大功告成!!!
有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!
-over-