Replies: 2 comments
-
I can't say for certain but having worked with zip libraries (Python's zipfile, golang's archive/zip), the only way to delete a file is to do what you have just described, creating a temporary archive and copying the files you want to it. Looking through zip-rs docs I also don't see anything that can let you delete files from a archive in place. |
Beta Was this translation helpful? Give feedback.
-
Having read more on zip files, it seems that they were originally designed to allow for file deletions by simply re-writing the file out of the central directory, but leaving the file data effectively orphaned within the archive. It was designed this way as writing to disk used to be the bottle-neck. I note the library doesn't include this functionality, but in this day & age I also don't think it should either. I ended up writing more or less the following code. I wonder if this should be added to the examples folder, perhaps linking to this discussion // Open the source archive
let zipfile = File::open(filename)?;
let mut archive = zip::ZipArchive::new(zipfile)?;
// Open a new, empty archive for writing to
let new_filename = "something_new.zip";
let new_file = File::create(&new_filename)?;
let mut new_archive = zip::ZipWriter::new(new_file);
// Loop through the original archive:
// - Write the target file from a vector of bytes
// - Copy everything else across as raw, which saves the bother of decoding it
// The end effect is to have a new archive, which is a clone of the original,
// save for the target file which has been re-written
const TARGET_PATH: &str = "some/path/within/the/zip.txt"
let target: &Path = TARGET_PATH.as_ref();
let new = b"Lorem ipsum";
for i in 0..archive.len() {
let file = archive.by_index_raw(i)?;
match file.enclosed_name() {
Some(p) if p == target => {
new_archive.start_file(TARGET_PATH, zip::write::FileOptions::default())?;
new_archive.write_all(&new)?;
new_archive.flush()?;
}
_ => new_archive.raw_copy_file(file)?,
}
}
new_archive.finish()?;
drop(archive);
drop(new_archive);
// If we're doing this in place then overwrite the original with the new
let inplace = false;
if inplace {
std::fs::rename(new_filename, filename)?;
} |
Beta Was this translation helpful? Give feedback.
-
Reading through the source code there doesn't appear to be a way to remove or replace a file from an archive. My use case is really the latter although I'll take delete and re-create.
The only plan I have to get round this is to open a new archive & loop through the existing archive calling
ZipWriter::raw_copy_file()
on all but the file I wish to modify. It seems a bit wasteful though.I'd appreciate it if you could point out what I've missed or a better way of achieving the same. Apologies in advance if this is a stupid question
Beta Was this translation helpful? Give feedback.
All reactions