Search code examples
rustzip

How to read specific file from zip file


I'm totally stuck reading a file from a variable path structure of a zip file without decompressing it.

My file is located here:

/info/[random-string]/info.json

Where [random-string] is the only file in the info folder. So its like read the 'info' folder read the first folder read the 'info.json'.

Any ideas how to do that with one of these libraries (zip or rc_zip)?

let file_path = file.to_str().unwrap();
let file = File::open(file_path).unwrap();
let reader = BufReader::new(file);

let mut archive = zip::ZipArchive::new(reader).unwrap();
let info_folder = archive.by_name("info").unwrap();
// how to list files of info_folder

Solution

  • Here you are:

    use std::error::Error;
    use std::ffi::OsStr;
    use std::fs::File;
    use std::path::Path;
    use zip::ZipArchive; // zip 0.5.13
    
    fn main() -> Result<(), Box<dyn Error>> {
        let archive = File::open("./info.zip")?;
        let mut archive = ZipArchive::new(archive)?;
    
        // iterate over all files, because you don't know the exact name
        for idx in 0..archive.len() {
            let entry = archive.by_index(idx)?;
            let name = entry.enclosed_name();
            
            if let Some(name) = name {
                // process only entries which are named  info.json
                if name.file_name() == Some(OsStr::new("info.json")) {
                    // the ancestors() iterator lets you walk up the path segments
                    let mut ancestors = name.ancestors();
                   
                    // skip self - the first entry is always the full path
                    ancestors.next(); 
    
                    // skip the random string
                    ancestors.next(); 
    
                    let expect_info = ancestors.next(); 
    
                    // the reminder must be only 'info/' otherwise this is the wrong entry
                    if expect_info == Some(Path::new("info/")) {
                        // do something with the file
                        println!("Found!!!");
                        break;
                    }
                }
            }
        }
    
        Ok(())
    }