All formats

libzip

LanguageC (usable from C++)
LicenseBSD 3-clause
Repositorygithub.com/nih-at/libzip
Documentationlibzip.org/documentation
Depends onzlib; optional bzip2, liblzma, zstd, OpenSSL / GnuTLS / mbed TLS / Windows CNG (for AES)
Read / writeyes / yes, ZIP64, AES-128/192/256 and ZipCrypto, stored, DEFLATE, bzip2, LZMA, XZ, Zstandard

libzip reads, creates and modifies ZIP archives. Changes (add, replace, rename, delete) are collected and written when you call zip_close, which writes a new archive to a temporary file and replaces the original. That makes it the best C library for editing existing archives. PHP’s ZipArchive is built on libzip.

The API uses zip_t for an archive, zip_file_t for an entry opened for reading, and zip_source_t for data to add (a buffer, a file or a custom callback). Entries are addressed by index (zip_uint64_t) or name.

Installation#

Shell
# Debian / Ubuntu
sudo apt install libzip-dev
# Fedora
sudo dnf install libzip-devel
# macOS
brew install libzip
# Windows (vcpkg)
vcpkg install libzip

With CMake:

cmake
find_package(libzip REQUIRED)
target_link_libraries(myapp PRIVATE libzip::zip)

Basic usage: list and read files#

C
#include <zip.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int err = 0;
    zip_t *za = zip_open("in.zip", ZIP_RDONLY, &err);
    if (!za) {
        zip_error_t error;
        zip_error_init_with_code(&error, err);
        fprintf(stderr, "cannot open: %s\n", zip_error_strerror(&error));
        zip_error_fini(&error);
        return 1;
    }

    zip_int64_t n = zip_get_num_entries(za, 0);
    for (zip_int64_t i = 0; i < n; i++) {
        zip_stat_t st;
        if (zip_stat_index(za, i, 0, &st) == 0) {
            printf("%-40s %10llu -> %10llu bytes\n", st.name,
                   (unsigned long long)st.size, (unsigned long long)st.comp_size);
        }
    }

    // read one file into memory
    zip_stat_t st;
    if (zip_stat(za, "readme.txt", 0, &st) == 0) {
        char *buf = malloc(st.size + 1);
        zip_file_t *zf = zip_fopen(za, "readme.txt", 0);
        if (buf && zf && zip_fread(zf, buf, st.size) == (zip_int64_t)st.size) {
            buf[st.size] = 0;
            printf("%s\n", buf);
        }
        if (zf) zip_fclose(zf);
        free(buf);
    }
    zip_close(za);
    return 0;
}

How to create a ZIP file#

Sources passed to zip_file_add are read when zip_close writes the archive, so buffers must stay valid until then:

C
#include <zip.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    int err = 0;
    zip_t *za = zip_open("out.zip", ZIP_CREATE | ZIP_TRUNCATE, &err);
    if (!za) return 1;

    const char *text = "hello from libzip\n";
    zip_source_t *src = zip_source_buffer(za, text, strlen(text), 0);
    if (!src || zip_file_add(za, "hello.txt", src, ZIP_FL_ENC_UTF_8) < 0) {
        zip_source_free(src);  // only free on failure; on success the archive owns it
        fprintf(stderr, "add failed: %s\n", zip_strerror(za));
    }

    zip_dir_add(za, "docs", ZIP_FL_ENC_UTF_8);
    src = zip_source_file(za, "report.pdf", 0, ZIP_LENGTH_TO_END);
    if (!src || zip_file_add(za, "docs/report.pdf", src, ZIP_FL_ENC_UTF_8) < 0) {
        zip_source_free(src);
    }

    if (zip_close(za) < 0) {  // the archive is written here
        fprintf(stderr, "write failed: %s\n", zip_strerror(za));
        zip_discard(za);
        return 1;
    }
    return 0;
}

How to set the compression method and level#

C
zip_int64_t idx = zip_file_add(za, "data.bin", src, ZIP_FL_OVERWRITE);
if (idx >= 0) {
    // ZIP_CM_STORE, ZIP_CM_DEFLATE, ZIP_CM_BZIP2, ZIP_CM_LZMA, ZIP_CM_XZ, ZIP_CM_ZSTD
    if (zip_compression_method_supported(ZIP_CM_ZSTD, 1))
        zip_set_file_compression(za, idx, ZIP_CM_ZSTD, 19);
    else
        zip_set_file_compression(za, idx, ZIP_CM_DEFLATE, 9);
}

Level 0 means the default for the method. Stick with DEFLATE when the archive must open in Windows Explorer or macOS.

How to create and read a password-protected ZIP (AES)#

C
// writing: encrypt one entry with AES-256
zip_int64_t idx = zip_file_add(za, "secret.txt", src, 0);
zip_file_set_encryption(za, idx, ZIP_EM_AES_256, "my password");

// reading: set a default password for all entries, then read normally
zip_set_default_password(za, "my password");
zip_file_t *zf = zip_fopen(za, "secret.txt", 0);

Other methods: ZIP_EM_AES_128, ZIP_EM_AES_192, ZIP_EM_TRAD_PKWARE (ZipCrypto, weak). AES needs libzip built with a crypto backend; check with zip_encryption_method_supported(ZIP_EM_AES_256, 1).

How to delete or rename a file inside a ZIP#

C
zip_t *za = zip_open("in.zip", 0, &err);  // open for modification
zip_int64_t idx = zip_name_locate(za, "old.txt", 0);
if (idx >= 0) zip_file_rename(za, idx, "new.txt", ZIP_FL_ENC_UTF_8);
idx = zip_name_locate(za, "unwanted.log", 0);
if (idx >= 0) zip_delete(za, idx);
zip_close(za);  // writes the changes

Tips#