Introduction
- To open an existing archive, call the CZipArchive::Open(LPCTSTR) method and specify one of
the following CZipArchive::OpenMode flags as the mode parameter:
- CZipArchive::zipOpen to open an archive for extraction and possibly for modifications.
- CZipArchive::zipOpenReadOnly to open an archive for reading only. It is useful when the archive
is locked by another application or during extracting the same archive from multiple threads.
- For the information about creating and extracting segmented archives, see Segmented Archives: Splitting and Spanning.
- For the information about processing archives in memory see In-Memory Archive Processing.
- You should call CZipArchive::Close() after you have finished working with an archive. To read
how to safely close an archive if an exception was thrown while processing an archive, see Exceptions Handling.
- When a compression method used in an archive is not supported by the ZipArchive library, the CZipArchive::Open(LPCTSTR)
method returns false. This allows reading local header information without throwing an exception. To check separately, if
the compression method is not supported, call the CZipCompressor::IsCompressionSupported()
method providing as the argument CZipFileHeader::m_uMethod value.
- To extract files from archives that are not entirely consistent (the library throws the CZipException::badZipFile)
exception, use the
CZipArchive::SetIgnoredConsistencyChecks() method to suppress certain checks.
- To extract JavaTM Archive (JAR) files, instruct the ZipArchive Library to ignore CRC
checking with the method CZipArchive::SetIgnoredConsistencyChecks() using the CZipArchive::checkCRC value.
- If you find that the ZipArchive Library does not extract all files from the archive created by external software, then most
probably an incorrect number of files is written in the archive itself. To deal with this situation, try using the CZipArchive::SetSpecialFlags() method with the CZipArchive::sfExhaustiveRead
flag.
- You can set advanced options for the decompression process with the CZipArchive::SetCompressionOptions()
method. See Compressing Data for more information.
- Extracted directories under Linux/OS X always receive 0755 permissions.
Easy Extraction
To quickly extract a file from an archive, use the
CZipArchive::ExtractFile(ZIP_INDEX_TYPE, LPCTSTR) method or its overload. You need to specify
an index of the file to decompress and the destination location. Additionally, you may specify:
- whether to extract the file with the full path information or not,
- a new name for the extracted file - it can be different from the original filename.
Sample Code
CZipArchive zip;
zip.Open(_T("C:\\Temp\\test.zip"));
zip.ExtractFile(0, _T("C:\\Temp"));
zip.ExtractFile(1, _T("C:\\Temp"), false, _T("just extracted.dat"));
zip.Close();
Callbacks Called
The methods for easy extraction can call the
CZipActionCallback::cbExtract callback to notify
about the progress. To read more about using callback objects, see
Progress Notifications: Using Callback Objects.
Advanced Extraction: More Control Over How Data is Read
The
CZipArchive::ExtractFile(ZIP_INDEX_TYPE, LPCTSTR) method and its overload do most of the
work for you, however you may want to have more control over this process. To manually extract a file follow these steps:
- Open an existing file in an archive with the CZipArchive::OpenFile() method. Make sure, the
method returns
true
.
- Extract the data by calling the CZipArchive::ReadFile() method. You can use this method in
two ways:
- by repeatedly calling it until it returns
0
- by calling it once using the uncompressed size (CZipFileHeader::m_uUncomprSize) and checking
that the same value is returned by this method. To make sure that the decompression was correct, you may call this method
once more, to ensure that it returns
0
.
- When there is no more data to extract, call the CZipArchive::CloseFile() method.
- Examine the return value from this method to ensure that the extraction process was successful. It should equal to
1
.
- If an exception was thrown while extracting data, call this method with the
bAfterException
parameter set to
true
, to prevent further exceptions being thrown when closing.
Sample Code
CZipArchive zip;
zip.Open(_T("C:\\Temp\\test.zip"));
zip.OpenFile(0);
DWORD uSize = (DWORD)zip[0]->m_uUncomprSize;
CZipAutoBuffer buffer;
buffer.Allocate(uSize);
try
{
if (zip.ReadFile(buffer, uSize) != uSize)
CZipException::Throw();
char temp;
if (zip.ReadFile(&temp, 1) != 0)
CZipException::Throw();
if (zip.CloseFile() != 1)
CZipException::Throw();
zip.Close();
CZipFile file;
file.Open(_T("C:\\Temp\\file.out"),
CZipFile::modeCreate | CZipFile::modeWrite, true);
file.Write(buffer, uSize);
}
catch(...)
{
zip.Close(CZipArchive::afAfterException);
throw;
}
Shared and Multithreaded Extraction
You can share one copy of the central directory between multiple
CZipArchive objects that refer
to the same archive. You can then open the same archive from multiple threads and perform read operations (such as extracting
or testing) minimizing this way memory usage and improving the performance (the central directory is read only once from
the disk). To benefit from this feature, perform the following steps:
The sample code below illustrates the idea (it does not contain the code that starts extraction asynchronously in multiple
threads).
Sample Code
void RunThread(ZIP_INDEX_TYPE uStartIdx, ZIP_INDEX_TYPE uEndIdx, CZipArchive& zip)
{
CZipArchive zipInThread;
zipInThread.OpenFrom(zip);
for (ZIP_INDEX_TYPE i = uStartIdx; i <= uEndIdx; i++)
zipInThread.ExtractFile(i, _T("C:\\Temp\\"), false);
}
void Multithreaded()
{
CZipArchive zip;
zip.Open(_T("C:\\Temp\\test.zip"), CZipArchive::zipOpenReadOnly);
if (zip.GetCount() == 0)
return;
const ZIP_INDEX_TYPE uFilesPerThread = 100;
ZIP_INDEX_TYPE uTotalFiles = zip.GetCount();
const int iLastThread = (int)(uTotalFiles / uFilesPerThread);
int iCurrentThread = 0;
bool bContinue = true;
for(;;)
{
ZIP_INDEX_TYPE uStartIdx = (ZIP_INDEX_TYPE)(iCurrentThread * uFilesPerThread);
ZIP_INDEX_TYPE uEndIdx;
if (iCurrentThread == iLastThread)
{
uEndIdx = zip.GetCount() - 1;
bContinue = false;
}
else
uEndIdx = uStartIdx + uFilesPerThread;
RunThread(uStartIdx, uEndIdx, zip);
if (bContinue)
iCurrentThread++;
else
break;
}
}
Additional Considerations
- You need to make sure that _ZIP_USE_LOCKING is defined in the _features.h
file to ensure a proper locking mechanism in multithreaded operations. It is not defined by default.
- The shared central directory keeps a reference count how many times it is used. Therefore, you don't have to open all subsequent
archives from the first object and you don't have to keep the first object opened all the time. You only need to make sure,
that the archive object you open from is opened. When the last of the CZipArchive objects sharing
the same central directory is destroyed, the central directory is removed from memory.
Testing Archives
To check, if a file inside an archive is correct, test the file with the
CZipArchive::TestFile()
method.
Sample Code
CZipArchive zip;
zip.Open(_T("C:\\Temp\\test.zip"));
bool ret = true;
for (ZIP_INDEX_TYPE index = 0; index < zip.GetCount(); index++)
{
try
{
if (!zip.TestFile(index))
{
ret = false;
break;
}
}
#ifdef _ZIP_IMPL_MFC
catch(CException* e)
{
e->Delete();
ret = false;
break;
}
#endif
catch(...)
{
ret = false;
break;
}
}
zip.Close();
return ret;
See Also API Links