#zip-archive #zip #archive #parallel #archive-format #thread

piz

piz(一个并行实现的Zip)是一个ZIP归档读取器,它使用简单的API并发地解压缩文件

8 个版本 (4 个重大更新)

0.5.1 2022年9月6日
0.5.0 2022年9月6日
0.4.0 2021年6月4日
0.3.1 2020年10月26日
0.1.0 2020年6月19日

#9 in #zip

Download history 1708/week @ 2024-03-14 1274/week @ 2024-03-21 1371/week @ 2024-03-28 1229/week @ 2024-04-04 1302/week @ 2024-04-11 1473/week @ 2024-04-18 1029/week @ 2024-04-25 1896/week @ 2024-05-02 1779/week @ 2024-05-09 844/week @ 2024-05-16 722/week @ 2024-05-23 842/week @ 2024-05-30 2334/week @ 2024-06-06 1545/week @ 2024-06-13 992/week @ 2024-06-20 1250/week @ 2024-06-27

6,179 每月下载量
2 crates 中使用

Zlib 许可证

64KB
976

piz:一个并行实现的Zip(在Rust中)

CI status

piz是一个ZIP归档读取器,它设计用来使用简单的API并发地解压缩任意数量的文件

// For smaller files,
//
//     let bytes = fs::read("foo.zip")
//     let archive = ZipArchive::new(&bytes)?;
//
// works just fine. Memory map larger files!
let zip_file = File::open("foo.zip")?;
let mapping = unsafe { Mmap::map(&zip_file)? };
let archive = ZipArchive::new(&mapping)?;

// We can iterate through the entries in the archive directly...
//
//     for entry in archive.entries() {
//         let mut reader = archive.read(entry)?;
//         // Read away!
//     }
//
// ...but ZIP doesn't guarantee that entries are in any particular order,
// that there aren't duplicates, that an entry has a valid file path, etc.
// Let's do some validation and organize them into a tree of files and folders.
let tree = as_tree(archive.entries())?;

// With that done, we can get a file (or directory)'s metadata from its path.
let metadata = tree.lookup("some/specific/file")?;
// And read the file out, if we'd like:
let mut reader = archive.read(metadata)?;
let mut save_to = File::create(&metadata.file_name)?;
io::copy(&mut reader, &mut save_to)?;

// Readers are `Send`, so we can read out as many as we'd like in parallel.
// Here we'll use Rayon to read out the whole archive with all cores:
tree.files()
    .par_bridge()
    .try_for_each(|entry| {
        if let Some(parent) = entry.file_name.parent() {
            // Create parent directories as needed.
            fs::create_dir_all(parent)?;
        }
        let mut reader = archive.read(entry)?;
        let mut save_to = File::create(&entry.file_name)?;
        io::copy(&mut reader, &mut save_to)?;
        Ok(())
    })?;

Zip是一个有趣的归档格式:与Linux领域常见的压缩tar包(如*.tar.gz*.tar.zst等)不同,Zip归档中的每个文件都是独立压缩的,中心目录告诉我们如何找到它们。这允许我们只要能同时从多个位置读取,就可以同时提取多个文件。

用户可以选择将整个归档读入内存,或者对于更大的归档,可以使用内存映射文件。(在64位系统上,即使文件比物理RAM大得多,这也允许我们将归档视为一个连续的字节范围。32位系统受地址空间限制,归档大小不能超过4GB,但只要归档足够小,piz应该表现得很好。)

示例

查看unzip/,其中包含一个简单的CLI示例,该示例将提供的文件解压缩到当前目录中。

测试

test_harness/ 包含一些针对几个输入的烟雾测试,例如:

  • 一些文本文件的基本、“Hello, Zip!”归档
  • 与一些垃圾数据预置相同的归档
  • 包含文件大于2^32字节的Zip64归档

如果没有找到这些文件,它将使用shell脚本创建它们(该脚本假定Unix环境)。

未来计划

Piz目前为每个文件提供有限的元数据(路径、大小、CRC32、最后修改时间等)。应稍后添加更多信息,如文件权限。也可以添加对DEFLATE以外的压缩算法(如Bzip2)的支持。

感谢

许多感谢

  • 汉斯·韦尔博格(Hans Wennborg)对他们的出色文章,Zip文件:历史、解释和实现

  • 马蒂·范·德·内斯(Mathijs van de Nes)的 zip-rs,这是本项目的灵感来源,也是Rust中Zip解码器的一个很好的例子

依赖关系

~1.9–3MB
~51K SLoC