Skip Navigation Links
Skip Navigation LinksHome > ZipArchive > How to Use > Article
Extracting Data and Testing Archives
Applies To: All

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 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;
// open an existing archive
zip.Open(_T("C:\\Temp\\test.zip"));
// extract the first file
zip.ExtractFile(0, _T("C:\\Temp"));
// extract the second file with the resulting filename changed
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;
// open an existing archive
zip.Open(_T("C:\\Temp\\test.zip"));
// open the first file in the archive for extraction
zip.OpenFile(0);
// for the simplicity of this example assume
// that the uncompressed size fits into the DWORD type
DWORD uSize = (DWORD)zip[0]->m_uUncomprSize;
CZipAutoBuffer buffer;
buffer.Allocate(uSize);
try
{
// decompress data
if (zip.ReadFile(buffer, uSize) != uSize)
CZipException::Throw();
char temp;
// check if all the data was decompressed
if (zip.ReadFile(&temp, 1) != 0)
// there is more data to decompress than declared
// this is an invalid zip archive
CZipException::Throw();
// check the return code to ensure that the extraction was
// successful
if (zip.CloseFile() != 1)
CZipException::Throw();
zip.Close();
// write the extracted file to the disk
CZipFile file;
file.Open(_T("C:\\Temp\\file.out"),
CZipFile::modeCreate | CZipFile::modeWrite, true);
file.Write(buffer, uSize);
}
// a simplified exception handler
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
// A thread method
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);
}
// Start threads
void Multithreaded()
{
CZipArchive zip;
// open an existing archive in the read-only mode
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;
// ....
// Here should come the code that asynchronously starts
// threads that execute the RunThread method
// ....
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;
// open an existing archive
zip.Open(_T("C:\\Temp\\test.zip"));
// test all files
bool ret = true;
for (ZIP_INDEX_TYPE index = 0; index < zip.GetCount(); index++)
{
try
{
if (!zip.TestFile(index))
{
ret = false;
break;
}
}
// a simplified exception handler
#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

Article ID: 0610241003
Back To Top Up