Быстрый способ упаковки содержимого папки в ZIP-архив

В wxWidgets есть такая отличная штука, как wxDirTraverser.
Что это и с чем его едят? Официальная документация говорит нам вот что:

wxDirTraverser is an abstract interface which must be implemented by objects passed to wxDir::Traverse() function.
Как по мне, довольно странное описание %), ничего толкового мы из него не узнаем. Тогда идем смотреть описание wxDir::Traverse():
Enumerate all files and directories under the given directory recursively calling the element of the provided wxDirTraverser object for each of them.
Уже лучше, оказывается, объект wxDirTraverser вызывается для каждого найденного объекта в указанном каталоге. Поиск выполняется рекурсивно для всех подкаталогов.
Итак, чем нам может помочь эта информация. Из документации видно, что у класса wxDirTraverser есть методы, которые вызываются для каждого файла или подкаталога (соответственно OnFile() и OnDir()), в которые передается путь найденного файла или каталога. Это значит что, получая имя каждого файла, мы можем сразу же добавить этот файл в архив без необходимости получения списка всех файлов и подкаталогов в массив (как мы бы сделали при использовании wxDir::GetAllFiles()).
Как это реализовано, смотрим ниже:

Dir Travaerser:

#ifndef _WX_DIR_TRAVERSER_ZIP_H
#define _WX_DIR_TRAVERSER_ZIP_H

#include <wx/wx.h>
#include <wx/dir.h>
#include <wx/zipstrm.h>
#include <wx/filename.h>
#include <wx/wfstream.h>

class wxDirTraverserZIP : public wxDirTraverser
{
public:
	wxDirTraverserZIP(wxZipOutputStream & stream, const wxString & baseDir) 
		: m_Stream(stream), m_BaseDir(baseDir) { }

	virtual wxDirTraverseResult OnFile(const wxString& filename)
	{
		do
		{
			wxFileName newFileName(filename);
			newFileName.MakeRelativeTo(m_BaseDir);
			if(!m_Stream.PutNextEntry(newFileName.GetFullPath()))
			{
				break;
			}
			wxFileInputStream in(filename);
			if(!in.IsOk()) 
			{
				break;
			}
			m_Stream.Write(in);
			return wxDIR_CONTINUE;
		}
		while(false);
		return wxDIR_STOP;
	}

	virtual wxDirTraverseResult OnDir(const wxString& dirname)
	{
		return wxDIR_CONTINUE;
	}

private:
	wxZipOutputStream & m_Stream;
	wxString m_BaseDir;
};

#endif

Usage:

bool PackFolder(const wxString & srcFolderName, const wxString & zipFileName)
{
	do
	{
		wxFFileOutputStream out(zipFileName);
		if(!out.IsOk()) break;
		wxCSConv conv(wxT("cp-866"));
		wxZipOutputStream zip(out, 9, conv);
		if(!zip.IsOk()) break;
		wxDirTraverserZIP traverser(zip, srcFolderName);
		wxDir srcDir(srcFolderName);
		if(srcDir.Traverse(traverser, wxEmptyString) == (size_t)-1) break;
		return true;
	}
	while(false);
	return false;
}
...
// Pack the folder
if(!PackFolder(wxT("c:\\test"), wxT("c:\\some.zip")))
{
//Handle error here
}

Creating Nice Reports with wxWidgets ZIP API

wxWidgets contains a set of classes which handle several archive formats. Most commonly used archive format is ZIP. This tutorial shows how to use wxWidgets API for reading and writing ZIP-files.
As you probably know, Microsoft Office 2007 produces .DOCX files which are ZIP archives which contain several XML files, images and few directories inside. After visiting Microsoft Developer’s Days I decided to add new feature to my current project and create new type of report which is based on .DOCX file format. This tutorial contains some techniques which you can use for generating such reports by yourself.
Continue reading…