开发者

Java - Reading multiple images from a single zip file and eventually turning them into BufferedImage objects. Good idea?

开发者 https://www.devze.com 2023-02-20 14:47 出处:网络
I\'m working on a game, and I need to load multiple image files (png, gif, etc.) that I\'ll eventually want to convert into BufferedImage objects.In my setup, I\'d like to load all of these images fro

I'm working on a game, and I need to load multiple image files (png, gif, etc.) that I'll eventually want to convert into BufferedImage objects. In my setup, I'd like to load all of these images from a single zip file, "Resources.zip". That resource file will contain images, map files, and audio files - all contained in various neatly ordered sub-directories. I want to do this because it will (hopefully) make resource loading easy in both applet and application versions of my program. I'm also hoping that for the applet version, this method will make it easy for me to show the loading progress of the game resources zip file (which could eventually amount to 10MB depending on how elaborate this game gets, though I'm hoping to keep it under that size so that it's browser-friendly).

I've included my zip handling class below. The idea is, I have a separate resource handling class, and it creates a ZipFileHandler object that it uses to pull specific resources out of the Resources.zip file.

import java.io.BufferedInputStream;
import java.io.File;
import java.io.开发者_JAVA百科IOException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class ZipFileHandler
{
private ZipFile zipFile;

public ZipFileHandler(String zipFileLocation)
{
    try
    {
        zipFile = new ZipFile(zipFileLocation);
    }
    catch (IOException e) {System.err.println("Unable to load zip file at location: " + zipFileLocation);}
}

public byte[] getEntry(String filePath)
{
    ZipEntry entry = zipFile.getEntry(filePath);
    int entrySize = (int)entry.getSize();
    try
    {
        BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
        byte[] finalByteArray = new byte[entrySize];

        int bufferSize = 2048;
        byte[] buffer = new byte[2048];
        int chunkSize = 0;
        int bytesRead = 0;

        while(true)
        {
            //Read chunk to buffer
            chunkSize = bis.read(buffer, 0, bufferSize); //read() returns the number of bytes read
            if(chunkSize == -1)
            {
                //read() returns -1 if the end of the stream has been reached
                break;
            }

            //Write that chunk to the finalByteArray
            //System.arraycopy(src, srcPos, dest, destPos, length)
            System.arraycopy(buffer, 0, finalByteArray, bytesRead, chunkSize);

            bytesRead += chunkSize;
        }

        bis.close(); //close BufferedInputStream

        System.err.println("Entry size: " + finalByteArray.length);

        return finalByteArray;
    }
    catch (IOException e)
    {
        System.err.println("No zip entry found at: " + filePath);
        return null;
    }
}
}

And I use the ZipFileHandler class like this:

ZipFileHandler zfh = new ZipFileHandler(the_resourceRootPath + "Resources.zip");
    InputStream in = new ByteArrayInputStream(zfh.getEntry("Resources/images/bg_tiles.png"));

    try
    {
        BufferedImage bgTileSprite = ImageIO.read(in);
    }
    catch (IOException e)
    {
        System.err.println("Could not convert zipped image bytearray to a BufferedImage.");
    }

And the good news is, it works!

But I feel like there might be a better way to do what I'm doing (and I'm fairly new to working with BufferedInputStreams).

In the end, my question is this:

Is this even a good idea?

Is there a better way to load a whole bunch of game resource files in a single download/stream, in an applet- AND application-friendly way?

I welcome all thoughts and suggestions!

Thanks!


Taking multiple resources and putting in them in one compressed file is how several web applications work (i.e. GWT) It is less expensive to load one large file than multiple small ones. This assumes that you are going to use all those resources in your app. If not Lazy loading is also a viable alternative.
That being said, it is usually best to get the app working and then to profile to find where the bottlenecks are. If not you will end up with a lot of complicated code and it will take you a lot longer to get your app working. 10%-20% of the code takes 80-90% of the time to execute. You just don;t know which 10-20% that is until the project is mostly complete.
If your goal is to learn the technologies and tinker, then good going - looks good.


If you are using a Java program, it is usually considered good practice to bundle it as a jar file anyway. So why do not put your classes simply inside this jar file (in directories, of course). Then you can simply use

`InputStream stream = MayClass.class.getResourceAsStream(imagePath);`

to load the data for each image, instead of having to handle all the zip by yourself (and it also works for jars not actually on the file system, such as http url in applets).

I also assume the jar will be cached, but you should measure and compare the performance to your solution with an external zip file.

0

精彩评论

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