Search code examples
zipwxwidgets

How do you recursively zip up a directory using wxWidgets?


How do you recursively zip up a directory using wxWidgets? I would like to place the resulting zip file right next to the target directory at the same level. The only input is simply one char string which contains the path of the directory to be zipped.


Solution

  • There's probably lots of ways to do this, but the most straightforward way might be to combine a wxDirTraverser and a wxZipOutputStream. Basically cutting and pasting from the samples in the docs, the derived traverser class could look something like:

    class wxDirZipper : public wxDirTraverser
    {
        public:
            wxDirZipper(const wxString& zip_filename, const wxString& folder)
            {
                wxFileName folder_to_zip_filename(folder);
                folder_to_zip_filename.Normalize();
                m_folder=folder_to_zip_filename.GetFullPath();
                m_zip = new wxZipOutputStream(new wxFileOutputStream(zip_filename));
            }
    
            ~wxDirZipper()
            {
                delete m_zip;
            }
    
            wxDirTraverseResult OnFile(const wxString& filename) wxOVERRIDE
            {
                wxFileInputStream fis(filename);
                m_zip->PutNextEntry(Chop(filename));
                m_zip->Write(fis);
                return wxDIR_CONTINUE;
            }
    
            wxDirTraverseResult OnDir(const wxString& dirname) wxOVERRIDE
            {
                wxDir dir(dirname);
    
                if( !dir.HasFiles() && !dir.HasSubDirs() )
                {
                    m_zip->PutNextDirEntry(Chop(dirname));
                }
    
                return wxDIR_CONTINUE;
            }
    
        private:
            wxString Chop(const wxString& filename) const
            {
                wxFileName fullpath(filename);
                fullpath.Normalize();
                wxString temp = fullpath.GetFullPath();
                temp.Replace(m_folder,wxEmptyString);
    
                return temp;
            }
    
            wxZipOutputStream* m_zip;
            wxString m_folder;
    };
    

    You would then call this with something like:

    wxString folder_to_zip = <whatever>
    wxString zip_filename = folder_to_zip+".zip";
    
    wxDirZipper zipper( zip_filename, folder_to_zip );
    wxDir dir(folder_to_zip);
    dir.Traverse(zipper);
    

    This is a basic implementation, and there's lots of room for improvement. You could, for example check before overwriting the zip file or use wxZipEntry to set metadata for the entries.