#zip-archive #zip

zipit

Create and stream zip archives on the fly

7 unstable releases

0.4.0 Aug 30, 2023
0.3.1 Mar 21, 2022
0.2.1 Nov 16, 2021
0.1.1 Nov 15, 2021

#437 in Compression

Download history 112/week @ 2024-07-21 103/week @ 2024-07-28 49/week @ 2024-08-04 60/week @ 2024-08-11 45/week @ 2024-08-18 246/week @ 2024-08-25 168/week @ 2024-09-01 157/week @ 2024-09-08 146/week @ 2024-09-15 378/week @ 2024-09-22 134/week @ 2024-09-29 282/week @ 2024-10-06 232/week @ 2024-10-13 136/week @ 2024-10-20 92/week @ 2024-10-27 113/week @ 2024-11-03

579 downloads per month

MIT license

27KB
336 lines

Zipit

crates.io Documentation

🗄️ Create and stream a zip archive into an AsyncWrite 🗄️

zipit = "0.3"

Features

  • Stream on the fly an archive from multiple AsyncRead objects.
  • Single read / seek free implementation (the CRC and file size are calculated while streaming and are sent afterwards).
  • Archive size pre-calculation (useful if you want to set the Content-Length before streaming).
  • futures and tokio AsyncRead / AsyncWrite compatible. Enable either the futures-async-io or the tokio-async-io feature accordingly.

Limitations

  • No compression (stored method only).
  • Only files (no directories).
  • No customizable external file attributes.

Examples

File system

Write a zip archive to the file system using tokio::fs::File:

use std::io::Cursor;
use tokio::fs::File;
use zipit::{Archive, FileDateTime};

#[tokio::main]
async fn main() {
    let file = File::create("archive.zip").await.unwrap();
    let mut archive = Archive::new(file);
    archive.append(
        "file1.txt".to_owned(),
        FileDateTime::now(),
        &mut Cursor::new(b"hello\n".to_vec()),
    ).await.unwrap();
    archive.append(
        "file2.txt".to_owned(),
        FileDateTime::now(),
        &mut Cursor::new(b"world\n".to_vec()),
    ).await.unwrap();
    archive.finalize().await.unwrap();
}

Hyper

Stream a zip archive as a hyper response:

use std::io::Cursor;
use hyper::{header, Body, Request, Response, Server, StatusCode};
use tokio::io::duplex;
use tokio_util::io::ReaderStream;
use zipit::{archive_size, Archive, FileDateTime};

async fn zip_archive(_req: Request<Body>) -> Result<Response<Body>, hyper::http::Error> {
    let (filename_1, mut fd_1) = (String::from("file1.txt"), Cursor::new(b"hello\n".to_vec()));
    let (filename_2, mut fd_2) = (String::from("file2.txt"), Cursor::new(b"world\n".to_vec()));
    let archive_size = archive_size([
        (filename_1.as_ref(), fd_1.get_ref().len()),
        (filename_2.as_ref(), fd_2.get_ref().len()),
    ]);

    let (w, r) = duplex(4096);
    tokio::spawn(async move {
        let mut archive = Archive::new(w);
        archive
            .append(
                filename_1,
                FileDateTime::now(),
                &mut fd_1,
            )
            .await
            .unwrap();
        archive
            .append(
                filename_2,
                FileDateTime::now(),
                &mut fd_2,
            )
            .await
            .unwrap();
        archive.finalize().await.unwrap();
    });

    Response::builder()
        .status(StatusCode::OK)
        .header(header::CONTENT_LENGTH, archive_size)
        .header(header::CONTENT_TYPE, "application/zip")
        .body(Body::wrap_stream(ReaderStream::new(r)))
}

Dependencies

~0–6MB
~28K SLoC