开发者

How can I convert a JarInputStream to a JarFile without saving to disk?

I've got a Servlet on which a user can upload a .jar file to check its MANIFEST.MF.

I know the following would work:

JarInputStream in = new JarInputStream(new ByteArrayInputStream (fileItem.get()));
Manifest mf = in.getManifest(); 

Unfortunatel开发者_如何转开发y the getManifest() method parses for Key: Value and needs the ": " (colon+space), a simple colon is not enough. Since the mobile phones I'm working with also work if the MANIFEST.MF only has colons and not colon+space, I'd like to extract the MANIFEST.MF manually, but I don't want to save the file on disk.

If I'd have a JarFile, I could parse the Manifest via:

JarFile jarFile = new JarFile(fileName);
InputStream in = jarFile.getInputStream(jarFile.getEntry("META-INF/MANIFEST.MF"));
BufferedReader br = new BufferedReader(new InputStreamReader(in));

String line;
while ((line = br.readLine()) != null) {
    String[] splitAr = line.split(":", 0);
    // ...

But unfortunately I have no idea how I could convert a JarInputStream (or a ByteArrayInputStream) to a JarFile.


What I would try to do in this case:

  • iterate through all the entries in the jar using getNextEntry() -- not getNextJarEntry()! and see if you can reach the manifest this way
  • try to use a ZipInputStream instead which is more generic -- JarInputStream in fact extends it -- and that should give you access to get the META-INF/MANIFEST.MF file.


This is not supported by the standard API. The only way to construct a JarFile is by providing a File reference, and since the API does not provide an interface to create "special files" backed by for instance an InputStream, it is not possible to solve it.

If you're on a UNIX system, you could probably set up a device file some how, but you would lose portability.


  private static void copyFiles(JarInputStream in, JarOutputStream out)
    throws IOException
  {
    JarEntry inEntry;
    byte[] buffer = new byte[4096];

    while ((inEntry=(JarEntry)in.getNextEntry())!=null)
          {if (inEntry.getMethod()==0)
              {out.putNextEntry(new JarEntry(inEntry));
              }
           else
               {out.putNextEntry(new JarEntry(inEntry.getName()));
               }
           //InputStream data=in;//the call to ZipInputStream.getNextEntry() positions the InputStream at the start of the entry and therefore supplying the ZipInputStream is the equivalent of supplying a ZipEntry's InputStream.the ZipInputStream is smart enough to handle the entry's EOF downstream
           int num;
           while ((len=/*data*/in.read(buffer))>0)
                 {out.write(buffer, 0, len);
                 }
           out.flush();
          }
  }


You can read manifest from input stream as string an parse it by yourself

/**
 * Read JAR  manifest as String from input stream.
 * Like JarInputStream, assume that META-INF/MANIFEST.MF entry  should be either 
 * the first or the second entry (when preceded  by the dir META-INF/).
 */
def readManifestAsString(InputStream is) {
    def zip = new ZipInputStream(is);
    def e = zip.getNextEntry();
    if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
        e =  zip.getNextEntry();  
    if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
        byte[] bytes = getBytes(new BufferedInputStream(zip));
        return new String(bytes, "UTF8");
     }
}

byte[] getBytes(InputStream is) {
        byte[] buffer = new byte[8192];
        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
        int n;
        while ((n = is.read(buffer, 0, buffer.length)) != -1) {
            baos.write(buffer, 0, n);
        }
        return baos.toByteArray();
 }

JAR Manifest specification can be found here

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜