Max Levy
Max Levy

Reputation: 404

A Rust function to return an iterator over lines of a zipped file

I found code for a function that returns an iterator over the lines of a text file:

pub fn read_file_iterator(path: &str) -> io::Result<Lines<BufReader<File>>> {
    let file = File::open(path)?;
    let buf_reader = BufReader::new(file);
    // lines() returns an iterator over lines
    Ok(buf_reader.lines())
}

Having zero experience with Rust, I thought I could adopt this code for a file which is a part of a ZIP archive:

use std::io::prelude::*;
use std::io::{self, BufReader, Lines, Cursor};
use std::path::Path;
use zip::read::ZipFile;

pub fn read_zip_file(_filename: &Path) -> io::Result<Lines<BufReader<ZipFile>>> {
    let reader = Cursor::new(std::fs::read(_filename)?);

    let mut zip_archive = zip::ZipArchive::new(reader)?;

    assert_eq!(1, zip_archive.len());

    let zip_file: ZipFile = zip_archive.by_index(0).unwrap(); // E: `zip_archive` is borrowed here"

    let buf_reader = BufReader::new(zip_file);

    Ok(buf_reader.lines()) // E: returns a value referencing data owned by the current function
}

Building this code results in an error (see also the comments that reflect the error details):

cannot return value referencing local variable zip_archive

What is the right way of writing such a function?

Upvotes: 2

Views: 556

Answers (1)

Leśny Rumcajs
Leśny Rumcajs

Reputation: 2516

The issue is that read_zip_file is doing much more than the read_file_iterator - ZipFile mutably borrows zip_archive which then goes out of scope. ZipFile does not exist without ZipArchive. This is not allowed, as the borrow checker suggested.

One approach would be to unzip this particular file as a temporary (as your ordinary zip browser does) and then do the iteration as in your first snippet. If the file is small and you know it beforehand - you better just collect the data, with e.g. read_to_end which ZipFile implements.

Upvotes: 1

Related Questions