Reading ZIP File in Symbian OS
The most popular archive file format used these days is ZIP, originally created by Phil Katz from the modification of ARC format. Symbian OS provides a class, called CZipFile, to read ZIP file. This class is supported by Symbian since version 7.x. This article will show how to use CZipFile and give an example. You can compile and run the example in Series 60 2.x or UIQ 2.x.
Although CZipFile is documented in Symbian SDKs, the explanation is far from enough. Another challenge, there is no example how to use the class. That's why I write this article to share my experience reading ZIP file in Symbian OS. I hope this would be useful for you.
Reading ZIP File
Let's start with a simple case, open a ZIP file and display information of all the files inside the ZIP file. Firstly, we need to create a new instance of CZipFile. There is a two-phase constructor that you can use to create it.
CZipFile* zipFile = CZipFile::NewL(fileSession, aCompressedFile);
CleanupStack::PushL(zipFile);
The first parameter of the constructor is a session of File Server. The second parameter is the file name of the ZIP file.
Next, we have to get the iterator for the ZIP file to iterate all the files one by one. It can be done by calling CZipFile::GetMembersL(). The return value is an instance of CZipFileMemberIterator class.
CZipFileMemberIterator* members = zipFile->GetMembersL();
CleanupStack::PushL(members);
Note that the ownership of members will be passed to the caller, thus we have to delete it after we are done.
Now, how can we get the instance of each file? By calling CZipFileMemberIterator::NextL(). We have to call this method until it returns 0, which means there is no more file. Look at the following example:
CZipFileMember* member;
while ((member = members->NextL()) != 0)
{
console->Printf(
KInfoMessage,
member->Name(),
member->CompressedSize(), member->UncompressedSize());
delete member;
}
The example above prints the name, compressed size and uncompressed size of all the files in the ZIP file. Note that we have to delete member because the ownership is passed to caller.
Finally, don't forget to release all the resources that we have allocated.
CleanupStack::PopAndDestroy(); // members
CleanupStack::PopAndDestroy(); // zipFile
If we have a ZIP file that contains three file, i.e. Example.txt, Example.dat and Example.png, the output will look like this (you can download this ZIP file at the end of this article).
Example.txt - 11 - 11
Example.dat - 15 - 180
Example.png - 4393 - 4393
Reading a File from ZIP File
This section shows how to extract a specific file from a ZIP file. As the previous example, the first step is to create the instance of CZipFile.
CZipFile* zipFile = CZipFile::NewL(fileSession, aCompressedFile);
CleanupStack::PushL(zipFile);
Here, we don't need an iterator because we are interested only in a specific file. The method that we have to call to get the instance of it is CZipFile::CaseInsensitiveMemberL(). This method requires a parameter, that is the file name that you want to access.
CZipFileMember* member = zipFile->CaseInsensitiveMemberL(aFileName);
CleanupStack::PushL(member);
Once again, we have to delete member after we have finished using it.
The next step is to the input stream and use the Read() method to extract the file. The input stream of a file inside ZIP file is RZipFileMemberReaderStream. The method used to get the input stream is CZipFile::GetInputStreamL().
RZipFileMemberReaderStream* stream;
zipFile->GetInputStreamL(member, stream);
CleanupStack::PushL(stream);
The following code shows how to read the file. Before reading the file, the code allocates a buffer to store with the size of member->UncompressesedSize().
HBufC8* buffer = HBufC8::NewLC(member->UncompressedSize());
TPtr8 bufferPtr(buffer->Des());
User::LeaveIfError(stream->Read(bufferPtr, member->UncompressedSize()));
If your file is quite huge, do not use "one-shot" Read() like the example above. It is not good because it will block your program. Instead, read using a small block of buffer and do it inside an active object. This example use "one-shot" Read() for simplicity reason.
Now we have the extracted file in a buffer. You can use it right away, or alternatively you can write it to a file. Here is the example how to write it to a file.
RFile file;
User::LeaveIfError(file.Replace(fileSession, fileName, EFileWrite));
CleanupClosePushL(file);
User::LeaveIfError(file.Write(*buffer));
Finally, do not forget to release all the allocated resources.
CleanupStack::PopAndDestroy(5); // file, buffer, stream, member, zipFile
Example
The following file contains the complete source code of the two examples above. This example is a console program. The output of the compiled example is a standalone .exe file, ZipExample.exe. Copy this file to your device at c:\systems\programs or any other directories. Before running the example, make sure that you have copied \group\Example.zip to c:\data\Example.zip on your device too.
The example does two things, i.e.:
- Display information of all the files contained in c:\data\Example.zip. It is done in IteratorExampleL() function.
- Extract Example.txt from c:\data\Example.zip and save it to c:\data\Example.txt. It is done in ExtractionExampleL() function.
Further Reading
- .ZIP File Format Specification - specification from the creator of PKZIP, the first program that supports ZIP file.
- CZipFile - official documentation of class CZipFile from Symbian web site.