当使用 "std :: io :: Write" 时,如何跟踪写入的字节数?

8

在编写二进制文件格式时,检查已写入多少字节很有用(例如进行对齐),或者只是为了确保嵌套函数写入了正确的数据量。

是否有一种方法可以检查 std::io::Write 已经写入了多少字节?如果没有,那么包装写入器以跟踪已写入多少字节会是一个好方法?

2个回答

8

Write具有两个必需的方法:writeflush。由于write已经返回了已写入字节数,因此您只需要跟踪它:

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());
}

不要委托write_allwrite_fmt,因为它们不返回字节数量。委托它们会导致字节被写入但无法跟踪。


这也是一个很好的答案,将两个都标记为正确的会很不错! - ideasman42
@ideasman42 如果Seek不能被实现或者不可用,我也不介意你将这个标记为答案。 - wimh
@wimh 嗯,我不知道。接受答案取决于哪个对 OP 在他们的特定情况下最有帮助。赞同是针对未来人们发现有用的答案。 - Shepmaster
有没有定义这个结构体的板条箱?似乎很方便,我不想在每个地方重复造轮子。 - SOFe
@SOFe 可能有地方,但我不知道在哪里。 - Shepmaster
1
我最终为此制作了一个库:https://docs.rs/count-write - SOFe

6
如果您要写入的类型实现了std::io::Seek,则可以使用seek获取当前位置:
pos = f.seek(SeekFrom::Current(0))?;

Seek是由std::fs::File实现的(如果包装类型也实现了Seek,则还有std::io::BufWriter)。


因此,函数签名为:

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

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

需要添加Seek特性:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接