2017-02-12 41 views
6

Podczas zapisywania do formatu pliku binarnego przydatne jest sprawdzenie, ile bajtów zostało zapisanych (na przykład w celu wyrównania) lub po prostu zapewnienie, że funkcje zagnieżdżone zapisują poprawną ilość danych.Jak śledzić, ile bajtów zapisano przy użyciu "std :: io :: Write"?

Czy istnieje sposób sprawdzenia, czy std::io::Write wie, ile zostało napisane? Jeśli nie, jakie byłoby dobre podejście do zawijania pisarza, aby mógł śledzić, ile zapisano bajtów?

Odpowiedz

7

Write ma dwie wymagane metody: write i flush. Od write już zwraca liczbę zapisanych bajtów, wystarczy śledzić że:

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

Ważne jest, aby nie delegata write_all lub write_fmt bo to nie zwróci liczbę bajtów. Delegowanie ich umożliwi zapisywanie bajtów, a nie ich śledzenie.

+0

Jest to doskonała odpowiedź też, byłoby miło, aby zaznaczyć zarówno jako poprawne! – ideasman42

+0

@ ideasman42 Nie miałbym nic przeciwko, jeśli oznaczysz to jako odpowiedź, ponieważ dotyczy to również sytuacji, gdy 'Seek' nie jest lub nie może być zaimplementowany. – wimh

+0

@wimh eh, nie wiem. Akceptacja jest zgodna z tym, co pomaga OP najbardziej w ich konkretnym przypadku. Przychodzą do odpowiedzi, które przyszli ludzie uważają za przydatne. – Shepmaster

5

Jeśli typ piszesz do wdraża std::io::Seek, można użyć seek uzyskać aktualną pozycję:

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

Seek jest realizowany przez std::fs::File (i std::io::BufWriter jeśli owinięte typ implementuje Seek zbyt).


Tak Funkcja Podpis:

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

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

musi mieć cechę Seek dodania:

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