1. 使用 tar

  需要安装flate2tar库,可通过cargo add flate2cargo add tar 命令安装

[dependencies]
flate2 = "1.0.25"
tar = "0.4.38"

1.1 压缩目录为 tar

  压缩 /root/testtar目录内的内容到 archive.tar.gz 压缩包中。创建一个用 GzEncodertar::Builder 包裹的 File。使用 Builder::append_dir_all,将 /root/testtar目录内的内容递归添加到 backup/code路径下的归档文件中。在将数据写入压缩包 archive.tar.gz 之前,GzEncoder 负责清晰地将数据压缩。

  • /root/testtar目录结构如下:
/root/testtar/
├── Cargo.lock_copy
├── Cargo.toml_copy
└── src-rust
└── main.rs
  • 详细代码如下:
use flate2::write::GzEncoder;
use flate2::Compression;
use std::fs::File;
use tar::Builder;

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 = Builder::new(enc);
tar.append_dir_all("backup/code", "/root/testtar")?;
Ok(())
}
  • 运行命令如下,在当前目录下生成一个名为archive.tar.gz的压缩包
cargo run
  • 目录结构如下
├── Cargo.lock
├── Cargo.toml
├── archive.tar.gz
├── src
│ └── main.rs
└── target

1.2. 解压 tar

  从当前工作目录中的压缩包 archive.tar.gz,解压(GzDecoder)和提取(Archive::unpack)所有文件,并放在copy目录下。

use flate2::read::GzDecoder;
use std::fs::File;
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("./copy/")?;

Ok(())
}
  • 运行命令如下,解压到copy目录下
cargo run
  • 目录结构如下,可以看到目录包含backup/code
copy/
└── backup
└── code
├── Cargo.lock_copy
├── Cargo.toml_copy
└── src-rust
└── main.rs

1.3 从路径移除前缀时,解压 tar

  循环遍历 Archive::entries。使用 Path::strip_prefix 移除指定的路径前缀(bundle/logs)。最终,通过 Entry::unpack提取 tar::Entrytar 包中的内容)。此块代码需要安装error-chain库,通过error-chain 命令安装

[dependencies]
error-chain = "0.12.4"
flate2 = "1.0.25"
tar = "0.4.38"
use error_chain::error_chain;
use flate2::read::GzDecoder;
use std::fs::File;
use std::path::PathBuf;
use tar::Archive;

error_chain! {
foreign_links {
Io(std::io::Error);
StripPrefixError(::std::path::StripPrefixError);
}
}

fn main() -> Result<()> {
let file = File::open("archive.tar.gz")?;
let mut archive = Archive::new(GzDecoder::new(file));
let prefix = "backup/code";

println!("提取了以下文件:");
archive
.entries()?
.filter_map(|e| e.ok())
.map(|mut entry| -> Result<PathBuf> {
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(())
}
  • 运行命令如下,解压到copy目录下
cargo run
  • 输出结果如下:
提取了以下文件:
> src-rust
> src-rust/main.rs
> Cargo.lock_copy
> Cargo.toml_copy
  • 解压到当前目录的目录结构如下
├── Cargo.lock_copy
├── Cargo.toml_copy
├── src-rust
│ └── main.rs