如何使用java.util.jar.JarOutputStream
以编程方式创建JAR文件?我的程序生成的JAR文件看起来是正确的(它提取正常)但是当我尝试从中加载库时,Java抱怨它无法找到明确存储在其中的文件。如果我提取JAR文件并使用Sun的jar
命令行工具重新压缩它,则生成的库可以正常工作。简而言之,我的JAR文件出了问题。
请解释如何以编程方式创建JAR文件,并使用清单文件。
答案 0 :(得分:91)
事实证明JarOutputStream
有三个未记载的怪癖:
以下是创建Jar文件的正确方法:
public void run() throws IOException
{
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
JarOutputStream target = new JarOutputStream(new FileOutputStream("output.jar"), manifest);
add(new File("inputDirectory"), target);
target.close();
}
private void add(File source, JarOutputStream target) throws IOException
{
BufferedInputStream in = null;
try
{
if (source.isDirectory())
{
String name = source.getPath().replace("\\", "/");
if (!name.isEmpty())
{
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile: source.listFiles())
add(nestedFile, target);
return;
}
JarEntry entry = new JarEntry(source.getPath().replace("\\", "/"));
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
}
finally
{
if (in != null)
in.close();
}
}
答案 1 :(得分:10)
还有另一个“怪癖”要注意:所有JarEntry的名字都不应以“/".
开头例如:清单文件的jar条目名称是“META-INF / MANIFEST.MF”而不是“/META-INF/MANIFEST.MF”。
所有jar条目都应遵循相同的规则。
答案 2 :(得分:2)
以下是使用JarOutputStream创建JAR文件的示例代码:
答案 3 :(得分:1)
您可以使用以下代码执行此操作:
public void write(File[] files, String comment) throws IOException {
FileOutputStream fos = new FileOutputStream(PATH + FILE);
JarOutputStream jos = new JarOutputStream(fos, manifest);
BufferedOutputStream bos = new BufferedOutputStream(jos);
jos.setComment(comment);
for (File f : files) {
print("Writing file: " + f.toString());
BufferedReader br = new BufferedReader(new FileReader(f));
jos.putNextEntry(new JarEntry(f.getName()));
int c;
while ((c = br.read()) != -1) {
bos.write(c);
}
br.close();
bos.flush();
}
bos.close();
// JarOutputStream jor = new JarOutputStream(new FileOutputStream(PATH + FILE), manifest);
}
PATH
变量:JAR文件的路径
FILE
变量:名称和格式
答案 4 :(得分:0)
此答案将解决相对路径问题。
private static void createJar(File source, JarOutputStream target) {
createJar(source, source, target);
}
private static void createJar(File source, File baseDir, JarOutputStream target) {
BufferedInputStream in = null;
try {
if (!source.exists()){
throw new IOException("Source directory is empty");
}
if (source.isDirectory()) {
// For Jar entries, all path separates should be '/'(OS independent)
String name = source.getPath().replace("\\", "/");
if (!name.isEmpty()) {
if (!name.endsWith("/")) {
name += "/";
}
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile : source.listFiles()) {
createJar(nestedFile, baseDir, target);
}
return;
}
String entryName = baseDir.toPath().relativize(source.toPath()).toFile().getPath().replace("\\", "/");
JarEntry entry = new JarEntry(entryName);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
} catch (Exception ignored) {
} finally {
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
throw new RuntimeException(ignored);
}
}
}
}
答案 5 :(得分:0)
好,因此,根据要求,这是Gili的代码,已修改为使用相对路径而不是绝对路径。 (将“ inputDirectory”替换为您选择的目录。)我刚刚对其进行了测试,但是如果它不起作用,我就知道了。
public void run() throws IOException
{
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
JarOutputStream target = new JarOutputStream(new FileOutputStream("output.jar"), manifest);
File inputDirectory = new File("inputDirectory");
for (File nestedFile : inputDirectory.listFiles())
add("", nestedFile, target);
target.close();
}
private void add(String parents, File source, JarOutputStream target) throws IOException
{
BufferedInputStream in = null;
try
{
String name = (parents + source.getName()).replace("\\", "/");
if (source.isDirectory())
{
if (!name.isEmpty())
{
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile : source.listFiles())
add(name, nestedFile, target);
return;
}
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
}
finally
{
if (in != null)
in.close();
}
}