README 未给出 CMake 之外的构建方式,非 CMake 项目需自行把 3 个源文件加入编译;密码保护仅支持传统 PKWARE 加密,不是 AES;Go/Rust/Ruby 等语言绑定需自行编译动态库并链接 libzip

mkdir build && cd build && cmake -DBUILD_SHARED_LIBS=true .. && cmake --build .README 未说明,纯 C 库,不涉及 GPU 或显存要求
一个可移植的 C 语言 zip 库,只需三个文件就能编进项目,省去引入重型依赖
用 C 写的轻量级 zip 压缩解压库,代码可移植、接口简单,方便嵌进各种 C 项目里处理 zip 文件。
核心能力
- 基于 miniz 封装,仅需 3 个源文件即可集成
- 支持把多个文件或缓冲区合并到同一 entry 并即时压缩
- 提供内存流 API,可直接在内存中创建和读取 zip
- 支持按名称或索引删除归档内条目
- 支持传统 PKWARE 加密的密码保护归档
容易踩的坑
- v0.3.15+miniz.3.1.2最新正式版2026-08-01 · 2026-08-01 14:10 UTC
What's Changed
- return actual decompressed size in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/406
- reject path-escaping entry names in unzipcli extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/407
- Change zip_name_normalize to accept const char* by @kuba-- in https://github.com/kuba--/zip/pull/409
- avoid signed-int overflow shifting mode bits in zip_entry_fwrite by @jmestwa-coder in https://github.com/kuba--/zip/pull/411
- strip setuid/setgid/sticky bits when restoring archived modes by @jmestwa-coder in https://github.com/kuba--/zip/pull/410
- fix non-terminating inflate loop in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/412
- guard against empty-archive underflow in zip_entry_finalize by @jmestwa-coder in https://github.com/kuba--/zip/pull/413
- avoid signed overflow in zip_pkware_decrypt_byte by @jmestwa-coder in https://github.com/kuba--/zip/pull/414
- reject overlong entry names in zip_entry_open by @jmestwa-coder in https://github.com/kuba--/zip/pull/415
- verify crc of decrypted entry in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/417
- reject out-of-range local header offset before delete by @jmestwa-coder in https://github.com/kuba--/zip/pull/418
- update central dir capacity after shrink in zip_central_dir_move by @jmestwa-coder in https://github.com/kuba--/zip/pull/419
- fix infinite loop in zip_entry_noallocreadwithoffset on corrupt entry by @jmestwa-coder in https://github.com/kuba--/zip/pull/420
- reject dataless symlink entries in zip_archive_extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/421
- avoid offset+size overflow in zip_entry_noallocreadwithoffset by @jmestwa-coder in https://github.com/kuba--/zip/pull/422
- reset move_length between runs in zip_entries_delete_mark by @jmestwa-coder in https://github.com/kuba--/zip/pull/423
- fix duplicate file_index in zip_index_update by @jmestwa-coder in https://github.com/kuba--/zip/pull/424
- harden and optimize entry delete path by @kuba-- in https://github.com/kuba--/zip/pull/425
- reject overlong entry paths in zip_archive_extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/427
- fix central-dir offsets array size in zip_central_dir_delete by @jmestwa-coder in https://github.com/kuba--/zip/pull/428
- treat backslash as a literal byte in zip_symlink_target_escapes by @jmestwa-coder in https://github.com/kuba--/zip/pull/429
- match only S_IFLNK in zip_stat_is_symlink by @jmestwa-coder in https://github.com/kuba--/zip/pull/426
- compact entries in local-header order in zip_entries_delete_mark by @jmestwa-coder in https://github.com/kuba--/zip/pull/431
- fix survivor offset compaction in zip_central_dir_delete by @jmestwa-coder in https://github.com/kuba--/zip/pull/432
- don't realloc the caller's buffer in zip_stream_delete_write_func by @jmestwa-coder in https://github.com/kuba--/zip/pull/433
- reject entry names that normalize to empty in zip_archive_extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/436
- Upgrade miniz 3.1.2 by @kuba-- in https://github.com/kuba--/zip/pull/438
- reject descend-then-climb targets in zip_symlink_target_escapes by @jmestwa-coder in https://github.com/kuba--/zip/pull/439
- reject a symlink at the destination path in zip_archive_extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/437
- add m_file_archive_start_ofs to raw file seeks on modify by @jmestwa-coder in https://github.com/kuba--/zip/pull/440
- avoid size_t overflow in zip_central_dir_move middle-run check by @jmestwa-coder in https://github.com/kuba--/zip/pull/442
- reject directory entries in the noalloc entry readers by @jmestwa-coder in https://github.com/kuba--/zip/pull/441
- copy the caller buffer before in-place moves in zip_files_move by @jmestwa-coder in https://github.com/kuba--/zip/pull/443
- salt the pkware encryption header per entry in _z
- v0.3.14+miniz.3.1.12026-06-21 · 2026-06-21 12:53 UTC
查看更新说明
What's Changed
- avoid offset+size overflow in zip_entry_noallocreadwithoffset by @jmestwa-coder in https://github.com/kuba--/zip/pull/422
- reset move_length between runs in zip_entries_delete_mark by @jmestwa-coder in https://github.com/kuba--/zip/pull/423
- fix duplicate file_index in zip_index_update by @jmestwa-coder in https://github.com/kuba--/zip/pull/424
- harden and optimize entry delete path by @kuba-- in https://github.com/kuba--/zip/pull/425
Full Changelog: https://github.com/kuba--/zip/compare/v0.3.13...v0.3.14+miniz.3.1.1
- v0.3.13+miniz.3.1.12026-06-20 · 2026-06-20 16:04 UTC
查看更新说明
What's Changed
- verify crc of decrypted entry in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/417
- reject out-of-range local header offset before delete by @jmestwa-coder in https://github.com/kuba--/zip/pull/418
- update central dir capacity after shrink in zip_central_dir_move by @jmestwa-coder in https://github.com/kuba--/zip/pull/419
- fix infinite loop in zip_entry_noallocreadwithoffset on corrupt entry by @jmestwa-coder in https://github.com/kuba--/zip/pull/420
- reject dataless symlink entries in zip_archive_extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/421
Full Changelog: https://github.com/kuba--/zip/compare/v0.3.12...v0.3.13+miniz.3.1.1
- v0.3.12+miniz.3.1.12026-06-18 · 2026-06-18 10:17 UTC
查看更新说明
What's Changed
- return actual decompressed size in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/406
- reject path-escaping entry names in unzipcli extract by @jmestwa-coder in https://github.com/kuba--/zip/pull/407
- Change zip_name_normalize to accept const char* by @kuba-- in https://github.com/kuba--/zip/pull/409
- avoid signed-int overflow shifting mode bits in zip_entry_fwrite by @jmestwa-coder in https://github.com/kuba--/zip/pull/411
- strip setuid/setgid/sticky bits when restoring archived modes by @jmestwa-coder in https://github.com/kuba--/zip/pull/410
- fix non-terminating inflate loop in zip_entry_decrypt_and_read by @jmestwa-coder in https://github.com/kuba--/zip/pull/412
- guard against empty-archive underflow in zip_entry_finalize by @jmestwa-coder in https://github.com/kuba--/zip/pull/413
- avoid signed overflow in zip_pkware_decrypt_byte by @jmestwa-coder in https://github.com/kuba--/zip/pull/414
- reject overlong entry names in zip_entry_open by @jmestwa-coder in https://github.com/kuba--/zip/pull/415
Full Changelog: https://github.com/kuba--/zip/compare/v0.3.9...v0.3.12+miniz.3.1.1
- v0.3.11v0.3.11+miniz.3.1.12026-06-07 · 2026-06-07 12:49 UTC
查看更新说明
Full Changelog: https://github.com/kuba--/zip/compare/v0.3.10...v0.3.11
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
A portable (OSX/Linux/Windows/Android/iOS), simple zip library written in C
This is done by hacking awesome miniz library and layering functions on top of the miniz v3.1.2 API.
The Idea
It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it.
Examples
- Create a new zip archive with default compression level.
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
zip_entry_open(zip, "foo-1.txt");
{
const char *buf = "Some data here...\0";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
zip_entry_open(zip, "foo-2.txt");
{
// merge 3 files into one entry and compress them on-the-fly.
zip_entry_fwrite(zip, "foo-2.1.txt");
zip_entry_fwrite(zip, "foo-2.2.txt");
zip_entry_fwrite(zip, "foo-2.3.txt");
}
zip_entry_close(zip);
}
zip_close(zip);
- Append to the existing zip archive.
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
{
zip_entry_open(zip, "foo-3.txt");
{
const char *buf = "Append some data here...\0";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
}
zip_close(zip);
- Extract a zip archive into a folder.
int on_extract_entry(const char *filename, void *arg) {
static int i = 0;
int n = *(int *)arg;
printf("Extracted: %s (%d of %d)\n", filename, ++i, n);
return 0;
}
// From "foo.zip" on disk
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
// Or from memory
arg = 2;
zip_stream_extract(zipstream, zipstreamsize, "/tmp", on_extract_entry, &arg);
- Extract a zip entry into memory.
void *buf = NULL;
size_t bufsize;
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_read(zip, &buf, &bufsize);
}
zip_entry_close(zip);
}
zip_close(zip);
free(buf);
- Extract a zip entry into memory (no internal allocation).
unsigned char *buf;
size_t bufsize;
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
bufsize = zip_entry_size(zip);
buf = calloc(sizeof(unsigned char), bufsize);
zip_entry_noallocread(zip, (void *)buf, bufsize);
}
zip_entry_close(zip);
}
zip_close(zip);
free(buf);
- Extract a zip entry into memory using callback.
struct buffer_t {
char *data;
size_t size;
};
static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) {
struct buffer_t *buf = (struct buffer_t *)arg;
buf->data = realloc(buf->data, buf->size + size + 1);
assert(NULL != buf->data);
memcpy(&(buf->data[buf->size]), data, size);
buf->size += size;
buf->data[buf->size] = 0;
return size;
}
struct buffer_t buf = {0};
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_extract(zip, on_extract, &buf);
}
zip_entry_close(zip);
}
zip_close(zip);
free(buf.data);
- Extract a zip entry into a file.
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-2.txt");
{
zip_entry_fread(zip, "foo-2.txt");
}
zip_entry_close(zip);
}
zip_close(zip);
- Create a new zip archive in memory (stream API).
char *outbuf = NULL;
size_t outbufsize = 0;
const char *inbuf = "Append some data here...\0";
struct zip_t *zip = zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_write(zip, inbuf, strlen(inbuf));
}
zip_entry_close(zip);
/* copy compressed stream into outbuf */
zip_stream_copy(zip, (void **)&outbuf, &outbufsize);
}
zip_stream_close(zip);
free(outbuf);
- Extract a zip entry into memory (stream API).
char *buf = NULL;
size_t bufsize = 0;
struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_read(zip, (void **)&buf, &bufsize);
}
zip_entry_close(zip);
}
zip_stream_close(zip);
free(buf);
- Extract a partial zip entry
Reads up to size bytes of the entry starting at offset into a caller-owned
buffer (no internal allocation). size is clamped to the bytes remaining after
offset, so it is safe to pass a size larger than what is left in the entry. The
call returns the number of bytes actually written, or a negative error code (for
example when offset is past the end of the entry).
unsigned char buf[16];
size_t bufsize = sizeof(buf);
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
size_t offset = 4;
ssize_t nread = zip_entry_noallocreadwithoffset(zip, offset, bufsize, (void *)buf);
if (nread < 0) {
// offset out of range or read error
}
}
zip_entry_close(zip);
}
zip_close(zip);
- List of all zip entries
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
int i, n = zip_entries_total(zip);
for (i = 0; i < n; ++i) {
zip_entry_openbyindex(zip, i);
{
const char *name = zip_entry_name(zip);
int isdir = zip_entry_isdir(zip);
int issymlink = zip_entry_issymlink(zip);
unsigned long long size = zip_entry_size(zip);
unsigned int crc32 = zip_entry_crc32(zip);
}
zip_entry_close(zip);
}
zip_close(zip);
- Compress folder (recursively)
void zip_walk(struct zip_t *zip, const char *path) {
DIR *dir;
struct dirent *entry;
char fullpath[MAX_PATH];
struct stat s;
memset(fullpath, 0, MAX_PATH);
dir = opendir(path);
assert(dir);
while ((entry = readdir(dir))) {
// skip "." and ".."
if (!strcmp(entry->d_name, ".\0") || !strcmp(entry->d_name, "..\0"))
continue;
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
stat(fullpath, &s);
if (S_ISDIR(s.st_mode))
zip_walk(zip, fullpath);
else {
zip_entry_open(zip, fullpath);
zip_entry_fwrite(zip, fullpath);
zip_entry_close(zip);
}
}
closedir(dir);
}
- Delete zip archive entries.
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
// size_t indices[] = {0, 1, 2};
struct zip_t *zip = zip_open("foo.zip", 0, 'd');
{
zip_entries_delete(zip, entries, 3);
// you can also delete by index, instead of by name
// zip_entries_deletebyindex(zip, indices, 3);
}
zip_close(zip);
- Create a password-protected zip archive (Traditional PKWARE Encryption).
struct zip_t *zip = zip_open_with_password("secret.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', "password");
{
zip_entry_open(zip, "secret-1.txt");
{
const char *buf = "Classified data...\0";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
}
zip_close(zip);
- Extract a password-protected zip archive.
void *buf = NULL;
size_t bufsize;
struct zip_t *zip = zip_open_with_password("secret.zip", 0, 'r', "password");
{
zip_entry_open(zip, "secret-1.txt");
{
zip_entry_read(zip, &buf, &bufsize);
}
zip_entry_close(zip);
}
zip_close(zip);
free(buf);
- Password-protected archive in memory (stream API).
char *outbuf = NULL;
size_t outbufsize = 0;
struct zip_t *zip = zip_stream_open_with_password(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', "password");
{
zip_entry_open(zip, "secret-1.txt");
{
const char *buf = "Classified data...\0";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
zip_stream_copy(zip, (void **)&outbuf, &outbufsize);
}
zip_stream_close(zip);
/* read it back */
void *readbuf = NULL;
size_t readsize = 0;
zip = zip_stream_open_with_password(outbuf, outbufsize, 0, 'r', "password");
{
zip_entry_open(zip, "secret-1.txt");
{
zip_entry_read(zip, &readbuf, &readsize);
}
zip_entry_close(zip);
}
zip_stream_close(zip);
free(readbuf);
free(outbuf);
- Delete entries from a password-protected archive.
char *entries[] = {"obsolete.txt", "remove-me.dat"};
struct zip_t *zip = zip_open_with_password("secret.zip", 0, 'd', "password");
{
zip_entries_delete(zip, entries, 2);
}
zip_close(zip);
Bindings
Compile zip library as a dynamic library.
$ mkdir build
$ cd build
$ cmake -DBUILD_SHARED_LIBS=true ..
$ cmake --build .
Go (cgo)
Third party binding: kuba--/c-go-zip
package main
/*
#cgo CFLAGS: -I../src
#cgo LDFLAGS: -L. -lzip
#include <zip.h>
*/
import "C"
import "unsafe"
func main() {
path := C.CString("/tmp/go.zip")
zip := C.zip_open(path, 6, 'w')
entryname := C.CString("test")
C.zip_entry_open(zip, entryname)
content := "test content"
buf := unsafe.Pointer(C.CString(content))
bufsize := C.size_t(len(content))
C.zip_entry_write(zip, buf, bufsize)
C.zip_entry_close(zip)
C.zip_close(zip)
}
Rust (ffi)
extern crate libc;
use std::ffi::CString;
#[repr(C)]
pub struct Zip {
_private: [u8; 0],
}
#[link(name = "zip")]
extern "C" {
fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
fn zip_close(zip: *mut Zip) -> libc::c_void;
fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
fn zip_entry_write(
zip: *mut Zip,
buf: *const libc::c_void,
bufsize: libc::size_t,
) -> libc::c_int;
}
fn main() {
let path = CString::new("/tmp/rust.zip").unwrap();
let mode: libc::c_char = 'w' as libc::c_char;
let entryname = CString::new("test.txt").unwrap();
let content = "test content\0";
unsafe {
let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
{
zip_entry_open(zip, entryname.as_ptr());
{
let buf = content.as_ptr() as *const libc::c_void;
let bufsize = content.len() as libc::size_t;
zip_entry_write(zip, buf, bufsize);
}
zip_entry_close(zip);
}
zip_close(zip);
}
}
Ruby (ffi)
Install ffi gem.
$ gem install ffi
Bind in your module.
require 'ffi'
module Zip
extend FFI::Library
ffi_lib "./libzip.#{::FFI::Platform::LIBSUFFIX}"
attach_function :zip_open, [:string, :int, :char], :pointer
attach_function :zip_close, [:pointer], :void
attach_function :zip_entry_open, [:pointer, :string], :int
attach_function :zip_entry_close, [:pointer], :void
attach_function :zip_entry_write, [:pointer, :string, :int], :int
end
ptr = Zip.zip_open("/tmp/ruby.zip", 6, "w" )
status = Zip.zip_entry_open(ptr, "test")
content = "test content"
status = Zip.zip_entry_write(ptr, content, content.size())
Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)
Python (cffi)
Install cffi package
$ pip install cffi
Bind in your package.
import ctypes.util
from cffi import FFI
ffi = FFI()
ffi.cdef("""
struct zip_t *zip_open(const char *zipname, int level, char mode);
void zip_close(struct zip_t *zip);
int zip_entry_open(struct zip_t *zip, const char *entryname);
int zip_entry_close(struct zip_t *zip);
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
"""
)
Zip = ffi.dlopen(ctypes.util.find_library("zip"))
ptr = Zip.zip_open("/tmp/python.zip", 6, 'w')
status = Zip.zip_entry_open(ptr, "test")
content = "test content"
status = Zip.zip_entry_write(ptr, content, len(content))
Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)
Never (ffi)
extern "libzip.so" func zip_open(zipname: string, level: int, mode: char) -> c_ptr
extern "libzip.so" func zip_close(zip: c_ptr) -> void
extern "libzip.so" func zip_entry_open(zip: c_ptr, entryname: string) -> int
extern "libzip.so" func zip_entry_close(zip: c_ptr) -> int
extern "libzip.so" func zip_entry_write(zip: c_ptr, buf: string, bufsize: int) -> int
extern "libzip.so" func zip_entry_fwrite(zip: c_ptr, filename: string) -> int
func main() -> int
{
let content = "Test content"
let zip = zip_open("/tmp/never.zip", 6, 'w');
zip_entry_open(zip, "test.file");
zip_entry_fwrite(zip, "/tmp/test.txt");
zip_entry_close(zip);
zip_entry_open(zip, "test.content");
zip_entry_write(zip, content, length(content));
zip_entry_close(zip);
zip_close(zip);
0
}
Ring
The language comes with RingZip based on this library
load "ziplib.ring"
new Zip {
setFileName("myfile.zip")
open("w")
newEntry() {
open("test.c")
writefile("test.c")
close()
}
close()
}
Zig
$ zig build-exe main.zig -lc -lzip
const c = @cImport({
@cInclude("zip.h");
});
pub fn main() void {
var zip = c.zip_open("/tmp/zig.zip", 6, 'w');
defer c.zip_close(zip);
_ = c.zip_entry_open(zip, "test");
defer _ = c.zip_entry_close(zip);
const content = "test content";
_ = c.zip_entry_write(zip, content, content.len);
}
Odin
Third party binding: thechampagne/zip-odin
package main
foreign import lib "system:zip"
import "core:c"
foreign lib {
zip_open :: proc(zipname : cstring, level : c.int, mode : c.char) -> rawptr ---
zip_close :: proc(zip : rawptr) ---
zip_entry_open :: proc(zip : rawptr, entryname : cstring) -> c.int ---
zip_entry_close :: proc(zip : rawptr) -> c.int ---
zip_entry_write :: proc(zip : rawptr, buf : rawptr, bufsize : c.size_t) -> c.int ---
}
main :: proc() {
zip_file := zip_open("odin.zip", 6, 'w')
defer zip_close(zip_file)
zip_entry_open(zip_file, "test")
defer zip_entry_close(zip_file)
content := "test content";
zip_entry_write(zip_file, &content, len(content))
}
Nim
Third party binding: thechampagne/nimzip
$ nim c --passL:-lzip main.nim
proc zip_open(zipname: cstring, level: cint, mode: char): pointer {.importc.}
proc zip_close(zip: pointer) {.importc.}
proc zip_entry_open(zip: pointer, entryname: cstring): cint {.importc.}
proc zip_entry_close(zip: pointer): cint {.importc.}
proc zip_entry_write(zip: pointer, buf: pointer, bufsize: csize_t): cint {.importc.}
when isMainModule:
var zip = zip_open("/tmp/nim.zip", 6, 'w')
discard zip_entry_open(zip, "test")
let content: cstring = "test content";
discard zip_entry_write(zip, content, csize_t(len(content)))
discard zip_entry_close(zip)
zip_close(zip)
D
Third party binding: thechampagne/zip-d
$ dmd -L-lzip main.d
extern(C) void* zip_open(const(char)* zipname, int level, char mode);
extern(C) void zip_close(void* zip);
extern(C) int zip_entry_open(void* zip, const(char)* entryname);
extern(C) int zip_entry_close(void* zip);
extern(C) int zip_entry_write(void* zip, const(void)* buf, size_t bufsize);
void main()
{
void* zip = zip_open("/tmp/d.zip", 6, 'w');
scope(exit) zip_close(zip);
zip_entry_open(zip, "test");
scope(exit) zip_entry_close(zip);
string content = "test content";
zip_entry_write(zip, content.ptr, content.length);
}
Pascal
Third party binding: thechampagne/zip-pascal
program main;
{$linklib c}
{$linklib zip}
uses ctypes;
function zip_open(zipname:Pchar; level:longint; mode:char):pointer;cdecl;external;
procedure zip_close(zip:pointer);cdecl;external;
function zip_entry_open(zip:pointer; entryname:Pchar):longint;cdecl;external;
function zip_entry_close(zip:pointer):longint;cdecl;external;
function zip_entry_write(zip:pointer; buf:pointer; bufsize:csize_t):longint;cdecl;external;
const
content: Pchar = 'test content';
var
zip : pointer;
begin
zip := zip_open('/tmp/pascal.zip', 6, 'w');
zip_entry_open(zip, 'test');
zip_entry_write(zip, content, strlen(content));
zip_entry_close(zip);
zip_close(zip);
end.
lua
Third party binding: gynt/luamemzip
-- Loads the luamemzip.dll
zip = require("luamemzip")
content = "Test content"
z = zip.zip_stream_open(nil, 6, 'w')
zip.zip_entry_open(z, "test.content")
zip.zip_entry_write(z, content)
zip.zip_entry_close(z)
data = zip.zip_stream_copy(z)
zip.zip_close(z)
Optional features
The library supports three compile-time flags to strip unused functionality and reduce binary size. All features are enabled by default -- if you just drop the source files into your project and compile, everything works as before.
| Flag | Default | Effect when disabled (=0) |
|---|---|---|
ZIP_ENABLE_DEFLATE | 1 | Removes compression / archive-writing APIs (zip_entry_write, zip_entry_fwrite, zip_create, zip_entries_delete, …). Write and append modes ('w', 'a', 'd') return an error. |
ZIP_ENABLE_INFLATE | 1 | Removes decompression / extraction APIs (zip_entry_read, zip_entry_fread, zip_entry_extract, zip_extract, zip_stream_extract, …). Read mode ('r') returns an error. |
ZIP_HAVE_SYMLINK | 1 (Unix/macOS), 0 (Windows) | When disabled, symlink entries are extracted as regular file copies instead of creating actual symlinks. |
MINIZ_NO_STDIO | 0 | When defined, will disable miniz and zip.c's usage of stdio. |
With CMake:
# Extract-only build (no compression)
cmake .. -DZIP_ENABLE_DEFLATE=OFF
# Compress-only build (no extraction)
cmake .. -DZIP_ENABLE_INFLATE=OFF
# Disable symlink support
cmake .. -DZIP_HAVE_SYMLINK=OFF
Without CMake (compiler flags):
cc -DZIP_ENABLE_DEFLATE=0 -c zip.c
Or define before including the header:
#define ZIP_ENABLE_DEFLATE 0
#include "zip.h"
No ZIP64
By default, opening an archive for writing with the literal mode character 'w' will enable ZIP64 output.
Internally the library sets a write flag when the mode equals the literal 'w':
mz_uint wflags = (mode == 'w') ? MZ_ZIP_FLAG_WRITE_ZIP64 : 0;
To ensure the produced ZIP archive is NOT ZIP64, use the alternate mode value that selects the same semantic mode but does not compare equal to the literal 'w'.
The implementation accepts an alternate value in the switch labels (so the same behavior is selected), but only the literal 'w' triggers the automatic ZIP64 flag.
Convention:
- Use
'w' - 64(integer value 55) when callingzip_open,zip_stream_open, etc., to select write mode without enabling ZIP64. - The same pattern applies to other modes: use
'r' - 64,'a' - 64,'d' - 64to pick the non-ZIP64 variants.
Check out more cool projects which use this library
- Filament: Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and as efficient as possible on Android.
- Hermes JS Engine: Hermes is a JavaScript engine optimized for fast start-up of React Native apps on Android. It features ahead-of-time static optimization and compact bytecode.
- Monster Mash: New Sketch-Based Modeling and Animation Tool.
- Object-Oriented Graphics Rendering Engine: OGRE is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.
- Open Asset Import Library: A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
- PowerToys: Set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity.
- The Ring Programming Language: Innovative and practical general-purpose multi-paradigm language.
- The V Programming Language: Simple, fast, safe, compiled. For developing maintainable software.
- TIC-80: TIC-80 is a FREE and OPEN SOURCE fantasy computer for making, playing and sharing tiny games.
- Urho3D: Urho3D is a free lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D.
- and more...