As per the link : https://stackoverflow.com/a/1281295/1794012
I followed the instructions and created a jar file, the input directory where the source files for creating the jar is as follows,
when i am traversing through JarFile#entries method it is printing the following,
META-INF/MANIFEST.MF
D:/so/
D:/so/some.txt
but i created the jar file using jar tool
jar -cvf so_commond.jar so so/some.txt
added manifest
adding: so/(in = 0) (out= 0)(stored 0%)
adding: so/some.txt(in = 7) (out= 9)(deflated -28%)
Now i use JarFile#entries to iterate the entries, the following is the output
META-INF/ (this is not there when jar created by JarOutputStream)
META-INF/MANIFEST.MF
so/
so/some.txt
Could you please explain why the jar entry META-INF is shown only when jar is created by jar tool and does not shown when jar is created by JarOutputStream?
Code:
public static void main(String[] args){
run();
for(Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();){
System.out.println(e.nextElement().getName());
}
}
public static void run() throws IOException
{
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
JarOutputStream target = new JarOutputStream(new FileOutputStream("D:\\so.jar"),
manifest);
add(new File("D:\\so"), target);
target.close();
}
private static 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();
}
}
A Java Archive, or JAR file, contains all of the various components that make up a self-contained, executable Java application, deployable Java applet or, most commonly, a Java library to which any Java Runtime Environment can link.
JAR stands for Java ARchive. It's a file format based on the popular ZIP file format and is used for aggregating many files into one. Although JAR can be used as a general archiving tool, the primary motivation for its development was so that Java applets and their requisite components (.
To run a jar file you only need java.exe(windows). JDK is the development kit for Java and JRE is the runtime. JDK contains JRE.
Directories are optional in the zip file format. When using the zip
command line tool this can be configured with --no-dir-entries
.
To get a result similar to that produced by the jar -cvf so_commond.jar so so/some.txt
command , you can change the run
method in this way:
public static void run() throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
try ( JarOutputStream target = new JarOutputStream(new FileOutputStream("D:\\so.jar"))) {
if (manifest != null) {
ZipEntry e = new ZipEntry(MANIFEST_DIR);
e.setTime(System.currentTimeMillis());
e.setSize(0);
e.setCrc(0);
target.putNextEntry(e);
e = new ZipEntry(MANIFEST_NAME);
e.setTime(System.currentTimeMillis());
target.putNextEntry(e);
manifest.write(target);
target.closeEntry();
}
add(new File("D:\\so"), target);
target.close();
}
}
the above code require the following definitions:
import static java.util.jar.JarFile.MANIFEST_NAME;
// .. and in the Class
static final String MANIFEST_DIR = "META-INF/";
The reason is that the jar tool has a create
method that act this way:
https://github.com/geekerstar/OpenJdk-11/blob/a576af6f90dfa05a935b813d633d9c8aaa690f83/src/sun/tools/jar/Main.java#L847
/**
* Creates a new JAR file.
*/
void create(OutputStream out, Manifest manifest) throws IOException
{
try (ZipOutputStream zos = new JarOutputStream(out)) {
if (flag0) {
zos.setMethod(ZipOutputStream.STORED);
}
// TODO: check module-info attributes against manifest ??
if (manifest != null) {
if (vflag) {
output(getMsg("out.added.manifest"));
}
ZipEntry e = new ZipEntry(MANIFEST_DIR);
e.setTime(System.currentTimeMillis());
e.setSize(0);
e.setCrc(0);
zos.putNextEntry(e);
e = new ZipEntry(MANIFEST_NAME);
e.setTime(System.currentTimeMillis());
if (flag0) {
crc32Manifest(e, manifest);
}
zos.putNextEntry(e);
manifest.write(zos);
zos.closeEntry();
}
updateModuleInfo(moduleInfos, zos);
for (Entry entry : entries) {
addFile(zos, entry);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With