diff --git a/book.toml b/book.toml index fbbeecbe..5e439c80 100644 --- a/book.toml +++ b/book.toml @@ -17,7 +17,7 @@ line-numbers = true [output.html.fold] enable = true -level = 1 +level = 2 [rust] edition = "2021" #在线运行用2021版本的 diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8c0b8135..89e1ba93 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -270,6 +270,8 @@ - [命令行]() - [参数解析](cookbook/cmd/parsing.md) - [终端输出格式化](cookbook/cmd/ansi.md) + - [压缩](cookbook/compression/intro.md) + - [使用.tar包](cookbook/compression/tar.md) - [配置文件解析 todo](cookbook/config.md) - [编解码 todo](cookbook/encoding/intro.md) - [JSON](cookbook/encoding/json.md) diff --git a/src/cookbook/compression/intro.md b/src/cookbook/compression/intro.md new file mode 100644 index 00000000..aa2d4d8b --- /dev/null +++ b/src/cookbook/compression/intro.md @@ -0,0 +1,3 @@ +## 压缩 + +我们会对常用的压缩方法进行介绍,例如 `tar`, `gzip`, `lz4` 等。 \ No newline at end of file diff --git a/src/cookbook/compression/tar.md b/src/cookbook/compression/tar.md new file mode 100644 index 00000000..992d8ddc --- /dev/null +++ b/src/cookbook/compression/tar.md @@ -0,0 +1,77 @@ +# 使用tar包 + +## 解压 tar 包 +以下代码将解压缩( [GzDecoder](https://docs.rs/flate2/*/flate2/read/struct.GzDecoder.html) )当前目录中的 `archive.tar.gz` ,并将所有文件抽取出( [Archive::unpack](https://docs.rs/tar/*/tar/struct.Archive.html#method.unpack) )来后当入到当前目录中。 + +```rust,editable +use std::fs::File; +use flate2::read::GzDecoder; +use tar::Archive; + +fn main() -> Result<(), std::io::Error> { + let path = "archive.tar.gz"; + + let tar_gz = File::open(path)?; + let tar = GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + archive.unpack(".")?; + + Ok(()) +} +``` + +## 将目录压缩成 tar 包 +以下代码将 `/var/log` 目录压缩成 `archive.tar.gz`: + +- 创建一个 [File](https://doc.rust-lang.org/std/fs/struct.File.html) 文件,并使用 [GzEncoder](https://docs.rs/flate2/*/flate2/write/struct.GzEncoder.html) 和 [tar::Builder](https://docs.rs/tar/*/tar/struct.Builder.html) 对其进行包裹 +- 通过 [Builder::append_dir_all](https://docs.rs/tar/*/tar/struct.Builder.html#method.append_dir_all) 将 `/var/log` 目录下的所有内容添加到压缩文件中,该文件在 `backup/logs` 目录下。 +- [GzEncoder](https://docs.rs/flate2/*/flate2/write/struct.GzEncoder.html) 负责在写入压缩文件 `archive.tar.gz` 之前对数据进行压缩。 + +```rust,editable +use std::fs::File; +use flate2::Compression; +use flate2::write::GzEncoder; + +fn main() -> Result<(), std::io::Error> { + let tar_gz = File::create("archive.tar.gz")?; + let enc = GzEncoder::new(tar_gz, Compression::default()); + let mut tar = tar::Builder::new(enc); + tar.append_dir_all("backup/logs", "/var/log")?; + Ok(()) +} +``` + +## 解压的同时删除指定的文件前缀 +遍历目录中的文件 [Archive::entries](https://docs.rs/tar/*/tar/struct.Archive.html#method.entries),若解压前的文件名包含 `bundle/logs` 前缀,需要将前缀从文件名移除( [Path::strip_prefix](https://doc.rust-lang.org/std/path/struct.Path.html#method.strip_prefix) )后,再解压。 + + + +```rust,editable +use std::fs::File; +use std::path::PathBuf; +use flate2::read::GzDecoder; +use tar::Archive; + +fn main() -> Result<()> { + let file = File::open("archive.tar.gz")?; + let mut archive = Archive::new(GzDecoder::new(file)); + let prefix = "bundle/logs"; + + println!("Extracted the following files:"); + archive + .entries()? // 获取压缩档案中的文件条目列表 + .filter_map(|e| e.ok()) + // 对每个文件条目进行 map 处理 + .map(|mut entry| -> Result { + // 将文件路径名中的前缀移除,获取一个新的路径名 + let path = entry.path()?.strip_prefix(prefix)?.to_owned(); + // 将内容解压到新的路径名中 + entry.unpack(&path)?; + Ok(path) + }) + .filter_map(|e| e.ok()) + .for_each(|x| println!("> {}", x.display())); + + Ok(()) +} +``` \ No newline at end of file diff --git a/内容变更记录.md b/内容变更记录.md index 7370c55d..866c0e73 100644 --- a/内容变更记录.md +++ b/内容变更记录.md @@ -7,6 +7,8 @@ - 新增章节: [Cookbook - Vec排序](https://course.rs/cookbook/algos/sorting.html) - 新增章节: [Cookbook - 命令行参数解析](https://course.rs/cookbook/cmd/parsing.html) - 新增章节:[Cookbook - 终端输出格式化](https://course.rs/cookbook/cmd/ansi.html) +- 新增章节:[Cookbook - 压缩 tar 包](https://course.rs/cookbook/compression/tar.html) + ## 2022-03-29