Cargo.toml增加依赖
zip = "0.5.5"
#压缩目录使用
walkdir = "2"
use std::fs;
use std::fs::File;
use std::io::{copy, Read, Seek, Write};
use std::path::Path;
use std::str;
use walkdir::{DirEntry, WalkDir};
use zip::write::FileOptions;
/// 都没有进行错误处理,本例子是参考官方例子,其中压缩目录也是看官方例子使用了walkdir库
fn main() {
compress_dir(Path::new("d:/tmp"), Path::new("d:/tmp.zip"));
// compress_file(Path::new("d:/企业微信截图_15792418969249.png"), Path::new("d:/test.zip"));
extract(Path::new("d:/tmp.zip"), Path::new("d:/tmp1"));
}
/// 压缩文件夹
/// test文件夹下有a.jpg和b.txt 两个文件
/// 压缩成test.zip文件
fn compress_dir(src_dir: &Path, target: &Path) {
let zipfile = std::fs::File::create(target).unwrap();
let dir = WalkDir::new(src_dir);
zip_dir(&mut dir.into_iter().filter_map(|e| e.ok()), src_dir.to_str().unwrap(), zipfile);
}
/// 压缩文件
fn compress_file(src_dir: &Path, target: &Path) {
let zipfile = std::fs::File::create(target).unwrap();
let dir = WalkDir::new(src_dir);
// src_dir.parent().map( |p| println!("{:?}",p.to_str().unwrap()));
let prefix = src_dir.parent().map_or_else(||"/",|p|p.to_str().unwrap());
zip_dir(&mut dir.into_iter().filter_map(|e| e.ok()), prefix, zipfile);
}
fn zip_dir<T>(it: &mut dyn Iterator<Item=DirEntry>, prefix: &str, writer: T) -> zip::result::ZipResult<()>
where T: Write + Seek {
let mut zip = zip::ZipWriter::new(writer);
let options = FileOptions::default()
.compression_method(zip::CompressionMethod::Bzip2)//直接用了bzip2压缩方式,其它参看枚举
.unix_permissions(0o755);//unix系统权限
let mut buffer = Vec::new();
for entry in it {
let path = entry.path();
//zip压缩一个文件时,会把它的全路径当成文件名(在下面的解压函数中打印文件名可知)
//这里是去掉目录前缀
println!("prefix {:?} ...", prefix);
let name = path.strip_prefix(Path::new(prefix)).unwrap();
println!("name {:?} ...", name);
// Write file or directory explicitly
// Some unzip tools unzip files with directory paths correctly, some do not!
if path.is_file() {
println!("adding file {:?} as {:?} ...", path, name);
zip.start_file_from_path(name, options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut buffer)?;
zip.write_all(&*buffer)?;
buffer.clear();
} else if name.as_os_str().len() != 0 {//目录
// Only if not root! Avoids path spec / warning
// and mapname conversion failed error on unzip
println!("adding dir {:?} as {:?} ...", path, name);
zip.add_directory_from_path(name, options)?;
}
}
zip.finish()?;
Result::Ok(())
}
///解压
/// test.zip文件解压到d:/test文件夹下
///
fn extract(test: &Path, mut target: &Path) {
let zipfile = std::fs::File::open(&test).unwrap();
let mut zip = zip::ZipArchive::new(zipfile).unwrap();
if !target.exists() {
fs::create_dir_all(target).map_err(|e| {
println!("{}", e);
});
}
for i in 0..zip.len() {
let mut file = zip.by_index(i).unwrap();
println!("Filename: {} {:?}", file.name(), file.sanitized_name());
if file.is_dir() {
println!("file utf8 path {:?}", file.name_raw());//文件名编码,在windows下用winrar压缩的文件夹,中文文夹件会码(发现文件名是用操作系统本地编码编码的,我的电脑就是GBK),本例子中的压缩的文件再解压不会出现乱码
let target = target.join(Path::new(&file.name().replace("\\", "")));
fs::create_dir_all(target).unwrap();
} else {
let file_path = target.join(Path::new(file.name()));
let mut target_file = if !file_path.exists() {
println!("file path {}", file_path.to_str().unwrap());
fs::File::create(file_path).unwrap()
} else {
fs::File::open(file_path).unwrap()
};
copy(&mut file, &mut target_file);
// target_file.write_all(file.read_bytes().into());
}
}
}
fn create_dir(path: &Path) -> Result<(), std::io::Error> {
fs::create_dir_all(path)
}