I've been toying around with Java some and now I wanted to be able to load images just not from a folder, but from a zip archive as well, since Java has built in zip functions.
My problem is that I can't find a single example on how you would read data from a zip file into memory, but just tons of examples on how to write it out to disc.
http://www.devshed.com/c/a/Java/Zip-Meets-Java/2/
If you follow that link you can see a fairly clear example on writing to disc. The question is what do I do differently to make it store it in memory instead? I suspect the solution could be to make the buffer place the data in a file object but I can't quite tell how I would write it, if it even is possible.
Of course I could extract the data to disc first, then open them as normal, and then delete them when ending the program, but it seems like it should be possible to skip those steps and read it directly to memory.
My current idea is that zipentries are not uncompressed data so I have to do the inputstreaming to get the uncompressed data. I just don't know how to put the data from the inputstream into a file object.
http://www.java2s.com/Code/Java/File-Input-Output/Loadzipfileandscanzipfile.htm
This other link is similar in that it puts zip data from a buffer into a string with readLine(). But I suspect this is only useful for text files and resets the data in the string each time it is run. And I don't want any of that when loading images.
So if anyone has a useful link (I googled all evening without any luck) or could tell me how to put the zip data inside a file object (for each file in the zip naturally) I'd be grateful.
Create a ZipFile object for starters. That gives you access to the ZipEntry objects and through those you can get an InputStream for each file. Reading an InputStream into a byte[] is trivial, but you can also read it directly into an image.
I worked some more and got something that looks good, but I'm not sure how correct it is.
File ImageZip = fc.getSelectedFile();
try{
ZipFile ZipData = new ZipFile(ImageZip, ZipFile.OPEN_READ);
Enumeration ZipDataFiles = ZipData.entries();
while (ZipDataFiles.hasMoreElements())
{
ZipEntry entry = (ZipEntry) ZipDataFiles.nextElement();
jLabelRightComicName.setText("read " + key + " images from zip");
while(ZipData.getInputStream(entry).available() == 1)
try{
ZipImages[key] = ImageIO.read(ZipData.getInputStream(entry));
}
catch (IOException e) {
}
key++;
}
ZipData.close();
}
catch (IOException e) {
}
It seems to at least count up key for the same amount as there are files in my test zip file. But when I later try and use the imagebuffer ZipImages it seems like I just keep getting NullPointerException, which I assume means that I just collected a lot of null from the zip file?
Is there anything obviously wrong in that piece of code?
> Is there anything obviously wrong in that piece of code?
The indentation?
I can't tell if that was a troll.
Here's the list of errors which instantly catch the eye:
Actual bugs: zipData.close() should be inside a finally{} block in case a failure does occur. IOException should not be caught and ignored. key appears to be defined nowhere. available() cannot be used as a reliable means of determining if there is more data, and furthermore it isn't necessary in the first place.
Style issues: indenting has already been pointed out. Brace style (next line or trailing) is not consistent. Variable names do not begin with a lowercase letter. The collection of images may be better as a Map rather than an array.
>zipData.close() should be inside a finally{} block in case a failure does occur.
This sounds like a good thing to do, but it seems like I just get an endless loop this way. The compiler complains that the ZipData.close() isn't inside a try{} when I put it inside a finally{}. Seems odd to make a finally{try{ZipData.close()}} structure, since we just said having ZipData.close() in a try{} wouldn't always run it if failure occured. Or woulf finally{} force any try{} inside it to run?
>key appears to be defined nowhere.
It was just earlier in the code. I didn't want to post everything. Just trust me that I do not have any obvious compiler complaints.
>available() cannot be used as a reliable means of determining if there is more data, and furthermore it isn't necessary in the first place.
I read it wasn't reliable but it felt like I had to have something to determine when it was done reading. But apparently removing this while-check actually made my program work.
>The collection of images may be better as a Map rather than an array.
You might be right. In any case I just discovered that my images from the zip isn't in "numeric" order so I'll have to create some kind of sorting system and maybe Map is better for that? I'll look a bit into this.
Thank you.
> This sounds like a good thing to do, but it seems like I just get an endless loop this way. The compiler complains that the ZipData.close() isn't inside a try{} when I put it inside a finally{}. Seems odd to make a finally{try{ZipData.close()}} structure, since we just said having ZipData.close() in a try{} wouldn't always run it if failure occured. Or woulf finally{} force any try{} inside it to run?
If you make your method throw IOException you won't need to worry about this. You will only need try { do stuff } finally { close it }. This makes sense in the case of loading sprites as if you fail to load them, there's nothing more you can do so bombing out with an error is appropriate.
Beyond that, there are basically two patterns in the event where you do need to catch the exception.
Option 1:
try {
// do stuff
} catch (IOException e) {
// handle the error
} finally {
try {
// close resources
} catch (IOException e) {
// log and ignore
}
}
Option 2:
try {
try {
// do stuff
} finally {
// close resources
}
} catch (IOException e) {
// handle the error
}
Advantage of option 1 is that an exception during close() definitely won't cause failure. Advantage of option 2 is that there's less code.