Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep track of how many bytes written when using 'std::io::Write'?

Tags:

io

rust

When writing to a binary file-format, its useful to be able to check how many bytes have been written (for alignment for example), or just to ensure nested functions wrote the correct amount of data.

Is there a way to inspect std::io::Write to know how much has been written? If not, what would be a good approach to wrap the writer so it could track how many bytes have been written?

like image 874
ideasman42 Avatar asked Feb 12 '17 12:02

ideasman42


2 Answers

Write has two required methods: write and flush. Since write already returns the number of bytes written, you just track that:

use std::io::{self, Write};

struct ByteCounter<W> {
    inner: W,
    count: usize,
}

impl<W> ByteCounter<W>
    where W: Write
{
    fn new(inner: W) -> Self {
        ByteCounter {
            inner: inner,
            count: 0,
        }
    }

    fn into_inner(self) -> W {
        self.inner
    }

    fn bytes_written(&self) -> usize {
        self.count
    }
}

impl<W> Write for ByteCounter<W>
    where W: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let res = self.inner.write(buf);
        if let Ok(size) = res {
            self.count += size
        }
        res
    }

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

fn main() {
    let out = std::io::stdout();
    let mut out = ByteCounter::new(out);
    writeln!(&mut out, "Hello, world! {}", 42).unwrap();
    println!("Wrote {} bytes", out.bytes_written());
}

It's important to not delegate write_all or write_fmt because these do not return the count of bytes. Delegating them would allow bytes to be written and not tracked.

like image 72
Shepmaster Avatar answered Nov 05 '22 15:11

Shepmaster


If the type you write to implements std::io::Seek, you can use seek to get the current position:

pos = f.seek(SeekFrom::Current(0))?;

Seek is implemented by std::fs::File (and std::io::BufWriter if the wrapped type implements Seek too).


So the function signature:

use ::std::io::{Write, Seek, SeekFrom, Error};

fn my_write<W: Write>(f: &mut W) -> Result<(), Error> { ... }

Needs to have the Seek trait added:

fn my_write<W: Write + Seek>(f: &mut W) -> Result<(), Error> { ... }
like image 26
wimh Avatar answered Nov 05 '22 14:11

wimh