edit_xlsx/utils/
zip_util.rs

1use std::{fs, io};
2use std::fs::File;
3use std::io::{Read, Write};
4use std::path::Path;
5use walkdir::WalkDir;
6use zip::CompressionMethod;
7use zip::result::ZipError;
8use zip::write::FileOptions;
9
10pub(crate) fn extract_dir<P: AsRef<Path>>(file_path: P, target: &str) -> zip::result::ZipResult<String> {
11    // read file from file path
12    let file = File::open(&file_path)?;
13    let mut archive = zip::ZipArchive::new(file)?;
14    // construct a base path for extracted files
15    let base_path = Path::new(&target);
16    match fs::create_dir(&base_path) {
17        Err(why) => println!("! {:?}", why.kind()),
18        Ok(_) => {},
19    }
20    for i in 0..archive.len() {
21        let mut file = archive.by_index(i)?;
22        let out_path = match file.enclosed_name() {
23            Some(path) => path.to_owned(),
24            None => continue,
25        };
26        let out_path = &base_path.join(out_path);
27        {
28            let comment = file.comment();
29            if !comment.is_empty() {
30                println!("File {i} comment: {comment}");
31            }
32        }
33        if (*file.name()).ends_with('/') {
34            fs::create_dir_all(&out_path)?;
35        } else {
36            if let Some(p) = out_path.parent() {
37                if !p.exists() {
38                    fs::create_dir_all(p)?;
39                }
40            }
41            let mut outfile = fs::File::create(&out_path)?;
42            io::copy(&mut file, &mut outfile)?;
43        }
44        // Get and Set permissions
45        #[cfg(unix)]
46        {
47            use std::os::unix::fs::PermissionsExt;
48
49            if let Some(mode) = file.unix_mode() {
50                fs::set_permissions(&out_path, fs::Permissions::from_mode(mode))?;
51            }
52        }
53    }
54    let tmp_dir = base_path.to_str().ok_or(ZipError::FileNotFound)?.to_string();
55    Ok(tmp_dir)
56}
57
58pub(crate) fn zip_dir<P: AsRef<Path>>(prefix: &str, file_path: P) -> zip::result::ZipResult<()> {
59    let writer = File::create(&file_path)?;
60    let walk_dir = WalkDir::new(&prefix);
61    let it = walk_dir.into_iter();
62    let it = &mut it.filter_map(|e| e.ok());
63
64    let mut zip = zip::ZipWriter::new(writer);
65    let options = FileOptions::default()
66        .compression_method(CompressionMethod::Deflated)
67        .unix_permissions(0o755);
68
69    let mut buffer = Vec::new();
70    for entry in it {
71        let path = entry.path();
72        let name = path.strip_prefix(Path::new(prefix)).unwrap();
73        // Write file or directory explicitly
74        // Some unzip tools unzip files with directory paths correctly, some do not!
75        if path.is_file() {
76            // println!("adding file {path:?} as {name:?} ...");
77            #[allow(deprecated)]
78            zip.start_file_from_path(name, options)?;
79            let mut f = File::open(path)?;
80
81            f.read_to_end(&mut buffer)?;
82            zip.write_all(&buffer)?;
83            buffer.clear();
84        } else if !name.as_os_str().is_empty() {
85            // Only if not root! Avoids path spec / warning
86            // and mapname conversion failed error on unzip
87            // println!("adding dir {path:?} as {name:?} ...");
88            #[allow(deprecated)]
89            zip.add_directory_from_path(name, options)?;
90        }
91    }
92    zip.finish()?;
93    Ok(())
94}
95
96#[test]
97fn test() -> io::Result<()> {
98    let file = File::open("./examples/xlsx/accounting.xlsx")?;
99    // 创建 ZipArchive 对象
100    let mut archive = zip::ZipArchive::new(file)?;
101    let file_path = "xl/styles.xml";
102
103    for i in 0..archive.len() {
104        let mut file = archive.by_index(i)?;
105        println!("{}", file.name());
106        if file.name() == file_path {
107            let mut contents = String::new();
108            file.read_to_string(&mut contents)?;
109            println!("File contents: {}", contents);
110        }
111    }
112    // if let Some(mut file) = find_file(&mut archive, file_path)? {
113    //     // 读取文件内容
114    //     let mut contents = String::new();
115    //     file.read_to_string(&mut contents)?;
116    //     println!("File contents: {}", contents);
117    // } else {
118    //     println!("File not found: {}", file_path);
119    // }
120    Ok(())
121}