Skip to content
This repository was archived by the owner on Jun 2, 2024. It is now read-only.
This repository was archived by the owner on Jun 2, 2024. It is now read-only.

Buffering IO when modifying a zip archive #245

@hniksic

Description

@hniksic

I don't know what type to pass to ZipWriter::new_append(). Specifically:

  • When reading an archive, one calls ZipArcihve::new() with a type that implements Read and Seek, such as BufReader<File>.
  • When writing an archive, one calls ZipWriter::new() with a type that implements Write and Seek, such as BufWriter<File>.
  • When appending to an archive, one calls ZipWriter::new_append() with... what type?

The problem is that new_append() requires its argument to implement all of Read, Write, and Seek, and no buffering IO wrapper provided by the standard library satisfies those bounds. Just giving it File will work, but won't do any buffering, which is not something you'd want to use in production. External crates such as bufstream don't support seeking. Examples don't appear to show how to invoke ZipWriter::new_append(), and tests only call it with io::Cursor<Vec<u8>>.

Currently I am using this hack helper to achieve this. Is there an easier way?

use std::io::{self, BufReader, BufWriter, Read, Seek, Write};
use std::fs::File;

pub struct BufReadWrite {
    r: BufReader<File>,
    w: BufWriter<File>,
}

impl BufReadWrite {
    pub fn new(f: File) -> io::Result<Self> {
        let fr = f;
        let fw = fr.try_clone()?;
        Ok(BufReadWrite {
            r: BufReader::new(fr),
            w: BufWriter::new(fw),
        })
    }
}

impl Read for BufReadWrite {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.r.read(buf)
    }
}

impl Write for BufReadWrite {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.w.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.w.flush()
    }
}

impl Seek for BufReadWrite {
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        self.w.flush()?;
        // BufReader's implementation of Seek::seek() guarantees to immediately
        // seek the underlying handle even if the seek is within the buffer
        // bounds. This is why this `seek()` works for writing as well.
        self.r.seek(pos)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions