Introduction
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 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();
UNC Paths
To use UNC paths with this method, replace
\\ at the beginning
of the UNC path with
\\?\UNC\.
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 have little possibility
to interfere in this process. To manually extract a file follow these steps:
- Open an existing file in an archive with the CZipArchive::OpenFile()
method.
- Extract the data you want 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; however 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_ARCHIVE_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_ARCHIVE_MFC
catch(CException* e)
{
e->Delete();
ret = false;
break;
}
#endif
catch(...)
{
ret = false;
break;
}
}
zip.Close();
return ret;
See Also API Calls