Trabajo con archivos ZIP en Rust usando la biblioteca zip
Al desarrollar en Rust, a menudo surge la necesidad de empaquetar archivos en archivos ZIP o extraer datos de ellos. Esto puede ser necesario para distribuir software, crear copias de seguridad, procesar archivos subidos por el usuario o compilar paquetes. La biblioteca estándar de Rust no incluye herramientas integradas para trabajar con ZIP, sin embargo, el ecosistema ofrece una biblioteca potente y conveniente llamada zip.
En este artículo, analizaremos en detalle cómo usar la biblioteca zip para crear, leer y extraer archivos ZIP. Aprenderá cómo instalar la biblioteca, trabajar con archivos y directorios, manejar errores y gestionar la compresión.
Instalación de la biblioteca zip
Para comenzar, agregue la dependencia al archivo Cargo.toml de su proyecto:
[dependencies]zip = "2.2"La biblioteca tiene soporte activo y utiliza las capacidades modernas de Rust. Después de agregar la dependencia, puede importarla en el código:
use zip::ZipWriter;use zip::read::ZipArchive;use std::io::{Read, Write, BufWriter, BufReader};use std::fs::{self, File};Creación de un archivo ZIP
La creación de un archivo consta de varios pasos: abrir el archivo para escritura, inicializar ZipWriter, agregar archivos y finalizar la escritura. Veamos un ejemplo que empaqueta un archivo de texto:
use std::fs::File;use zip::ZipWriter;use zip::write::FileOptions;use std::io::Write;
fn create_archive() -> zip::result::ZipResult<()> { let file = File::create("example.zip")?; let mut zip = ZipWriter::new(file);
let options = FileOptions::default() .compression_method(zip::CompressionMethod::Deflated) .unix_permissions(0o755);
zip.start_file("hello.txt", options)?; zip.write_all(b"Hello, Rust ZIP!")?;
zip.finish()?; Ok(())}Aquí:
- Creamos el archivo
example.zipen el directorio actual. - Inicializamos
ZipWriter. - Configuramos los parámetros del archivo: método de compresión
Deflated(compresión estándar) y permisos de acceso. - Agregamos el archivo
hello.txty escribimos su contenido. - Finalizamos la escritura llamando a
finish().
Para agregar varios archivos o un directorio completo, use un bucle sobre los archivos en la carpeta:
fn add_directory(zip: &mut ZipWriter<File>, dir_path: &str) -> zip::result::ZipResult<()> { for entry in walkdir::WalkDir::new(dir_path) { let entry = entry?; let path = entry.path(); if path.is_file() { let name = path.strip_prefix(dir_path).unwrap().to_str().unwrap(); zip.start_file(name, FileOptions::default())?; let mut f = File::open(path)?; std::io::copy(&mut f, zip)?; } } Ok(())}Tenga en cuenta: para recorrer directorios de forma recursiva, es conveniente usar el crate walkdir, pero debe agregarse por separado.
Lectura y extracción de un archivo ZIP
Para leer un archivo se utiliza ZipArchive. A continuación se muestra un ejemplo que lista los archivos en el archivo y los extrae en una carpeta especificada:
use zip::ZipArchive;use std::io::Read;
fn extract_archive(archive_path: &str, output_dir: &str) -> zip::result::ZipResult<()> { let file = File::open(archive_path)?; let mut archive = ZipArchive::new(file)?;
for i in 0..archive.len() { let mut entry = archive.by_index(i)?; let entry_name = entry.name().to_string(); println!("Extrayendo: {}", entry_name);
// Creamos la ruta completa al archivo let output_path = format!("{}/{}", output_dir, entry_nam