一、JarFile 与 URL
JarFile 是 Java 提供的一个类,可以读取 jar 包中的所有文件(递归读取),然后提取指定的文件。
1.JarFile
使用 java.util.jar.JarFile 可读取 jar 内部的文件。若读取嵌套 jar 中的一个文件内容,则需要先把嵌套的 jar,写入临时文件,再从临时 jar 文件,读取其中的文件
@Test
public void testJarEntry() throws Exception {
JarFile jarFile = new JarFile("/home/zxm/IdeaProjects/parent/level1/target/level1-1.0.jar");
System.out.println("jarFile name:" + jarFile.getName());
// 遍历内部文件名称
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
System.out.println("entry name:" + name);
}
}
@Test
public void testReadJarFile() throws Exception {
JarFile jarFile = new JarFile("/home/zxm/IdeaProjects/parent/level1/target/level1-1.0.jar");
JarEntry jarEntry = jarFile.getJarEntry("t1.txt");
// 去读文件内容
if (jarEntry != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(jarFile.getInputStream(jarEntry)));
String line;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null) {
builder.append(line);
}
br.close();
System.out.println("content: " + builder);
} else {
System.out.println("t1.txt is not exist");
}
}
@Test
public void testNestedJarFile() throws Exception {
String outerJarFilePath = "/home/zxm/IdeaProjects/parent/level1/target/level1-1.0.jar";
String nestedJarFileName = "lib/level2-1.0.jar";
String targetFileName = "t2.txt";
JarFile outerJarFile = new JarFile(outerJarFilePath);
JarEntry nestedJarEntry = outerJarFile.getJarEntry(nestedJarFileName);
// 去读文件内容
if (nestedJarEntry != null) {
// 创建临时文件
File tempFile = File.createTempFile("inner_jar_", ".jar");
FileOutputStream tempOs = new FileOutputStream(tempFile);
InputStream tempIs = outerJarFile.getInputStream(nestedJarEntry);
byte[] buffer = new byte[1024];
int len;
while ((len = tempIs.read(buffer)) > 0) {
tempOs.write(buffer, 0, len);
}
tempOs.close();
tempIs.close();
// 打开内嵌JAR文件
JarFile nestedJarFile = new JarFile(tempFile);
JarEntry targetEntry = nestedJarFile.getJarEntry(targetFileName);
if (targetEntry != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(nestedJarFile.getInputStream(targetEntry)));
String line;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null) {
builder.append(line);
}
br.close();
System.out.println("content: " + builder);
} else {
System.out.println(targetFileName + " is not exist");
}
} else {
System.out.println(nestedJarFileName + " is not exist");
}
}
2.URL
java 支持使用 URL 定位到 jar 中一个文件,但不支持读取嵌套 jar 中的一个文件。如要读取嵌套 jar 中的一个文件,可注册 springboot jar Handler 可处理嵌套 jar 中的文件
@Test
public void testURL() throws Exception {
// 读取文件
URL url1 = new URL("jar:file:/home/zxm/IdeaProjects/parent/level1/target/level1-1.0.jar!/t1.txt");
BufferedReader br1 = new BufferedReader(new InputStreamReader(url1.openStream()));
String line1;
StringBuilder builder1 = new StringBuilder();
while ((line1 = br1.readLine()) != null) {
builder1.append(line1);
}
br1.close();
System.out.println("content: " + builder1);
// 注册 spring boot 的 JarFile Handler,支持读取嵌套 jar 的文件
org.springframework.boot.loader.jar.JarFile.registerUrlProtocolHandler();
URL url2 = new URL("jar:file:/home/zxm/IdeaProjects/parent/level1/target/level1-1.0.jar!/lib/level2-1.0.jar!/t2.txt");
BufferedReader br2 = new BufferedReader(new InputStreamReader(url2.openStream()));
String line2;
StringBuilder builder2 = new StringBuilder();
while ((line2 = br2.readLine()) != null) {
builder2.append(line2);
}
br2.close();
System.out.println("content: " + builder2);
}
若使用 springboot 的 jar handler,需要引入 spring-boot-loader
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>