web-dev-qa-db-fra.com

Un moyen simple de décompresser un fichier .Zip en utilisant zlib

Existe-t-il un exemple simple montrant comment décompresser un fichier .Zip et extraire les fichiers dans un répertoire? J'utilise actuellement zlib, et bien que je comprenne que zlib ne traite pas directement les fichiers Zip, il semble y avoir plusieurs choses supplémentaires dans la bibliothèque "contrib" de zlibs. J'ai remarqué et lu à propos de "minizip", et après avoir lu certains documents et examiné une partie du code, je ne vois pas un exemple simple illustrant la procédure à suivre pour décompresser un fichier .Zip et extraire les fichiers dans un répertoire.

Je voudrais trouver un moyen de le faire indépendant de la plate-forme, mais si cela n’est pas possible, je dois trouver un moyen pour Windows et Mac.

38
judeclarke

zlib gère l'algorithme de compression/décompression à dégonfler , mais il y a plus que cela dans un fichier Zip.

Vous pouvez essayer libzip . C'est gratuit, portable et facile à utiliser.

UPDATE: J'attache ici un exemple quick'n'dirty de libzip, avec tous les contrôles d'erreur ommited:

#include <Zip.h>

int main()
{
    //Open the Zip archive
    int err = 0;
    Zip *z = Zip_open("foo.Zip", 0, &err);

    //Search for the file of given name
    const char *name = "file.txt";
    struct Zip_stat st;
    Zip_stat_init(&st);
    Zip_stat(z, name, 0, &st);

    //Alloc memory for its uncompressed contents
    char *contents = new char[st.size];

    //Read the compressed file
    Zip_file *f = Zip_fopen(z, name, 0);
    Zip_fread(f, contents, st.size);
    Zip_fclose(f);

    //And close the archive
    Zip_close(z);

    //Do something with the contents
    //delete allocated memory
    delete[] contents;
}
49
rodrigo

Minizip a un exemple de programme pour démontrer son utilisation - les fichiers s'appellent minizip.c et miniunz.c.

Mise à jour: Comme je disposais de quelques minutes, je vous ai concocté cet exemple rapide et dénudé. C'est très odorant C, et je ne l'utiliserais pas sans améliorations majeures. J'espère que c'est suffisant pour vous aider pour le moment.

// uzip.c - Simple example of using the minizip API.
// Do not use this code as is! It is educational only, and probably
// riddled with errors and leaks!
#include <stdio.h>
#include <string.h>

#include "unzip.h"

#define dir_delimter '/'
#define MAX_FILENAME 512
#define READ_SIZE 8192

int main( int argc, char **argv )
{
    if ( argc < 2 )
    {
        printf( "usage:\n%s {file to unzip}\n", argv[ 0 ] );
        return -1;
    }

    // Open the Zip file
    unzFile *zipfile = unzOpen( argv[ 1 ] );
    if ( zipfile == NULL )
    {
        printf( "%s: not found\n" );
        return -1;
    }

    // Get info about the Zip file
    unz_global_info global_info;
    if ( unzGetGlobalInfo( zipfile, &global_info ) != UNZ_OK )
    {
        printf( "could not read file global info\n" );
        unzClose( zipfile );
        return -1;
    }

    // Buffer to hold data read from the Zip file.
    char read_buffer[ READ_SIZE ];

    // Loop to extract all files
    uLong i;
    for ( i = 0; i < global_info.number_entry; ++i )
    {
        // Get info about current file.
        unz_file_info file_info;
        char filename[ MAX_FILENAME ];
        if ( unzGetCurrentFileInfo(
            zipfile,
            &file_info,
            filename,
            MAX_FILENAME,
            NULL, 0, NULL, 0 ) != UNZ_OK )
        {
            printf( "could not read file info\n" );
            unzClose( zipfile );
            return -1;
        }

        // Check if this entry is a directory or file.
        const size_t filename_length = strlen( filename );
        if ( filename[ filename_length-1 ] == dir_delimter )
        {
            // Entry is a directory, so create it.
            printf( "dir:%s\n", filename );
            mkdir( filename );
        }
        else
        {
            // Entry is a file, so extract it.
            printf( "file:%s\n", filename );
            if ( unzOpenCurrentFile( zipfile ) != UNZ_OK )
            {
                printf( "could not open file\n" );
                unzClose( zipfile );
                return -1;
            }

            // Open a file to write out the data.
            FILE *out = fopen( filename, "wb" );
            if ( out == NULL )
            {
                printf( "could not open destination file\n" );
                unzCloseCurrentFile( zipfile );
                unzClose( zipfile );
                return -1;
            }

            int error = UNZ_OK;
            do    
            {
                error = unzReadCurrentFile( zipfile, read_buffer, READ_SIZE );
                if ( error < 0 )
                {
                    printf( "error %d\n", error );
                    unzCloseCurrentFile( zipfile );
                    unzClose( zipfile );
                    return -1;
                }

                // Write data to file.
                if ( error > 0 )
                {
                    fwrite( read_buffer, error, 1, out ); // You should check return of fwrite...
                }
            } while ( error > 0 );

            fclose( out );
        }

        unzCloseCurrentFile( zipfile );

        // Go the the next entry listed in the Zip file.
        if ( ( i+1 ) < global_info.number_entry )
        {
            if ( unzGoToNextFile( zipfile ) != UNZ_OK )
            {
                printf( "cound not read next file\n" );
                unzClose( zipfile );
                return -1;
            }
        }
    }

    unzClose( zipfile );

    return 0;
}

Je l'ai construit et testé avec MinGW/MSYS sur Windows comme ceci:

contrib/minizip/$ gcc -I../.. -o unzip uzip.c unzip.c ioapi.c ../../libz.a
contrib/minizip/$ ./unzip.exe /j/zlib-125.Zip
28
x-x