in Code

In-memory ZIP File Access Using Qt

A while ago I was working on a little tool to manage my media files – TV shows and movies that I’d ripped from my DVD collection that I wanted to make available through XBMC on my home theater system. To display things like plot, characters, runtime, etc., XBMC reads NFO files – which are just XML files – one for each media file. Entering this information by hand is not a fun afternoon activity, so I looked for a way to automate it. I found a couple of different sites that provided the data I needed via APIs and eventually settled on TheTVDB.com for TV series and themoviedb.org for movies. So all I needed to do was read the data using the APIs and write it to the NFO files. Simple!

For each TV series, TheTVDB provides a ZIP file containing several XML files which splits up the information to make it more manageable and allows for easier internationalization. A typical ZIP from TheTVDB contains files such as actors.xml, banners.xml, and en.xml. The actors.xml file contains a list of actors, the roles they play, a link to an image, etc.. banners.xml provides links to fan art and thumbnails which XBMC can use for display. en.xml provides the core data: a description of the TV series and a list of all the episodes from the series including plot, runtime, air date, etc. for each of them.

So what’s the best way to download and access this zipped data? One solution – I think the most obvious – is to download the ZIP file to a temp directory, unzip it either using a system command or a built-in ZIP implementation, then to read the XML file you’re interested in from the disk. One disadvantage with this solution is speed. Why unzip the whole file if you just want to read some data from one of the files in it? This just results in a bunch of unnecessary I/O. So my solution was to download the ZIP file to a temp directory, then simply read the XML file I wanted directly into a data structure without unpacking it.

I created a little class called asmZip to read a ZIP file and access a specific file within it. It is used like this:

I’d used minizip in a project years ago, so I decided to use it for unzipping. I downloaded v1.1 with zip64 support and unpacked it into the same directory as my source.

Next I added the files I needed (ioapi.[hc] and unzip.[hc]) to my qmake .pro file:

Here’s the header file for the asmZip class:

This is a pretty simple, straightforward class as there are only three public functions and a constructor. This could be expanded to do all sorts of interesting stuff with ZIP files, but for my project I only needed the capability to read a file from a ZIP into memory. I also included a method to list files in the ZIP which is a modified version from the minizip code which uses Qt classes.

The constructor and destructor handle the opening and closing of the ZIP file using the minizip functions. Note that the ZIP file will remain open for the duration of the existence of the asmZip instance, so if you don’t want that you can move the open and close code into their own functions.

This is the code which finds and extracts a file from a ZIP into a QByteArray. I’ve added debug statements to provide a bit of info on error, but you’ll want to handle this your own way. It also outputs a message to qDebug() when you extract a file:

Finally we have a couple of functions which are a quick-and-dirty translation to Qt to list the contents of a ZIP file.

Executing this member function will give you a list of files in the ZIP. Something like this:

I didn’t really need this for my project, but it can be useful to see what is in the ZIP, what other info you have access to, and how to access it.

That’s it! A simple little class using Qt to access files in-memory from the ZIP file instead of unpacking them.

I hope someone, somewhere finds it useful…

Leave a Reply for Rajiv Perseedoss Cancel Reply

Write a Comment

Comment

15 Comments

    • Been a long time since I looked at this, but I think each file within the archive is password protected. So I would change the call to unzOpenCurrentFile() to unzOpenCurrentFilePassword().

  1. After changing the code to minizip from github , asm_zip.cpp give the casting error below.

    • I guess they changed the signature of the function to make the comparison more generic.

      One option would be to write two unzFileNameComparer functions and pick the right one based on eCaseSensitivity inCaseSensitive.

      • I try looking into header file (unzip.h) and just find

        In unzip.c file , I found

        therefore I change the extractFile in asm_zip.cpp to

        but now I got link error below

        • I think all of those functions are zlib functions. zlib is installed on Mac OS X by default (and linked in the .pro with -lz on the Mac), but you’re on Windows.

          So you’ll need to download, install, and link your project to zlib.

  2. My QT creator said it doesn’t found ‘file_info’ in ‘asmZip.cpp’. Did I miss something in ‘.pro’ file?

    • Two things to check:

      1) Did you download the minizip code and add the files (ioapi.[hc] and unzip.[hc]) to your .pro?

      2) This is rather old – perhaps minizip has changed or it might be a Qt5 thing (this was written with Qt4)?

      Are there any other clues? Maybe you can paste in the actual error?

      • I am using QT 5.5.Here are some of the error message.

        and my “.pro” look like this

  3. Hi, thanks for sharing. You can access the method’s name via __FUNCTION__ macro for the debug output.

    • Thanks. The __FUNCTION__ macro is non-standard, so not all compilers support it. The C99 standard provides __func__, but I don’t know the state of adoption.