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()
-- notgetNextJarEntry()
! 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 theMETA-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
精彩评论