web-dev-qa-db-ja.com

zlibを使用して.Zipファイルを解凍する簡単な方法

.Zipファイルを解凍し、ディレクトリにファイルを抽出する方法の簡単な例はありますか?現在zlibを使用していますが、zlibはZipファイルを直接処理しないことを理解していますが、zlibsの「contrib」ライブラリにはいくつかの追加事項があるようです。 「minizip」について気づき、読みました。いくつかのドキュメントを読んで、いくつかのコードを調べた後、.Zipファイルを解凍してファイルをディレクトリに抽出する簡単な例は見当たりません。

プラットフォームに依存しない方法を見つけたいのですが、それが不可能な場合は、WindowsとMac用の方法を見つける必要があります。

38
judeclarke

zlibdeflate圧縮/解凍アルゴリズムを処理しますが、Zipファイルにはそれ以上のものがあります。

libzip を試すことができます。無料で、ポータブルで使いやすいです。

更新:ここでは、libzipのquick'n'dirtyの例を添付します。すべてのエラーコントロールは省略されています。

#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 には、その使用方法を示すサンプルプログラムがあります。ファイルの名前はminizip.cおよびminiunz.cです。

更新:数分でしたので、この素朴で素朴な例を紹介しました。これは非常に臭いのあるCであり、大幅な改善がなければ使用しません。うまくいけば、今のところあなたを連れて行くのに十分です。

// 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;
}

次のように、Windows上でMinGW/MSYSを使用して構築およびテストしました。

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