impl<W: Write> GzEncoder<W> { /// Creates a new encoder which will use the given compression level. /// /// The encoder is not configured specially for the emitted header. For /// header configuration, see the `GzBuilder` type. /// /// The data written to the returned encoder will be compressed and then /// written to the stream `w`. pubfn new(w: W, level: Compression) -> GzEncoder<W> {
GzBuilder::new().write(w, level)
}
/// Acquires a reference to the underlying writer. pubfn get_ref(&self) -> &W { self.inner.get_ref()
}
/// Acquires a mutable reference to the underlying writer. /// /// Note that mutation of the writer may result in surprising results if /// this encoder is continued to be used. pubfn get_mut(&mutself) -> &mut W { self.inner.get_mut()
}
/// Attempt to finish this output stream, writing out final chunks of data. /// /// Note that this function can only be used once data has finished being /// written to the output stream. After this function is called then further /// calls to `write` may result in a panic. /// /// # Panics /// /// Attempts to write data to this stream may result in a panic after this /// function is called. /// /// # Errors /// /// This function will perform I/O to complete this stream, and any I/O /// errors which occur will be returned from this function. pubfn try_finish(&mutself) -> io::Result<()> { self.write_header()?; self.inner.finish()?;
whileself.crc_bytes_written < 8 { let (sum, amt) = (self.crc.sum(), self.crc.amount()); let buf = [
(sum >> 0) as u8,
(sum >> 8) as u8,
(sum >> 16) as u8,
(sum >> 24) as u8,
(amt >> 0) as u8,
(amt >> 8) as u8,
(amt >> 16) as u8,
(amt >> 24) as u8,
]; let inner = self.inner.get_mut(); let n = inner.write(&buf[self.crc_bytes_written..])?; self.crc_bytes_written += n;
}
Ok(())
}
/// Finish encoding this stream, returning the underlying writer once the /// encoding is done. /// /// Note that this function may not be suitable to call in a situation where /// the underlying stream is an asynchronous I/O stream. To finish a stream /// the `try_finish` (or `shutdown`) method should be used instead. To /// re-acquire ownership of a stream it is safe to call this method after /// `try_finish` or `shutdown` has returned `Ok`. /// /// # Errors /// /// This function will perform I/O to complete this stream, and any I/O /// errors which occur will be returned from this function. pubfn finish(mutself) -> io::Result<W> { self.try_finish()?;
Ok(self.inner.take_inner())
}
fn write_header(&mutself) -> io::Result<()> { while !self.header.is_empty() { let n = self.inner.get_mut().write(&self.header)?; self.header.drain(..n);
}
Ok(())
}
}
impl<W: Write> Write for GzEncoder<W> { fn write(&mutself, buf: &[u8]) -> io::Result<usize> {
assert_eq!(self.crc_bytes_written, 0); self.write_header()?; let n = self.inner.write(buf)?; self.crc.update(&buf[..n]);
Ok(n)
}
impl<W: Write> Drop for GzEncoder<W> { fn drop(&mutself) { ifself.inner.is_present() { let _ = self.try_finish();
}
}
}
/// A decoder for a single member of a [gzip file]. /// /// This structure exposes a [`Write`] interface, receiving compressed data and /// writing uncompressed data to the underlying writer. /// /// After decoding a single member of the gzip data this writer will return the number of bytes up to /// to the end of the gzip member and subsequent writes will return Ok(0) allowing the caller to /// handle any data following the gzip member. /// /// To handle gzip files that may have multiple members, see [`MultiGzDecoder`] /// or read more /// [in the introduction](../index.html#about-multi-member-gzip-files). /// /// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html /// /// # Examples /// /// ``` /// use std::io::prelude::*; /// use std::io; /// use flate2::Compression; /// use flate2::write::{GzEncoder, GzDecoder}; /// /// # fn main() { /// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); /// # e.write(b"Hello World").unwrap(); /// # let bytes = e.finish().unwrap(); /// # assert_eq!("Hello World", decode_writer(bytes).unwrap()); /// # } /// // Uncompresses a gzip encoded vector of bytes and returns a string or error /// // Here Vec<u8> implements Write /// fn decode_writer(bytes: Vec<u8>) -> io::Result<String> { /// let mut writer = Vec::new(); /// let mut decoder = GzDecoder::new(writer); /// decoder.write_all(&bytes[..])?; /// writer = decoder.finish()?; /// let return_string = String::from_utf8(writer).expect("String parsing error"); /// Ok(return_string) /// } /// ``` #[derive(Debug)] pubstruct GzDecoder<W: Write> {
inner: zio::Writer<CrcWriter<W>, Decompress>,
crc_bytes: Vec<u8>,
header_parser: GzHeaderParser,
}
const CRC_BYTES_LEN: usize = 8;
impl<W: Write> GzDecoder<W> { /// Creates a new decoder which will write uncompressed data to the stream. /// /// When this encoder is dropped or unwrapped the final pieces of data will /// be flushed. pubfn new(w: W) -> GzDecoder<W> {
GzDecoder {
inner: zio::Writer::new(CrcWriter::new(w), Decompress::new(false)),
crc_bytes: Vec::with_capacity(CRC_BYTES_LEN),
header_parser: GzHeaderParser::new(),
}
}
/// Returns the header associated with this stream. pubfn header(&self) -> Option<&GzHeader> { self.header_parser.header()
}
/// Acquires a reference to the underlying writer. pubfn get_ref(&self) -> &W { self.inner.get_ref().get_ref()
}
/// Acquires a mutable reference to the underlying writer. /// /// Note that mutating the output/input state of the stream may corrupt this /// object, so care must be taken when using this method. pubfn get_mut(&mutself) -> &mut W { self.inner.get_mut().get_mut()
}
/// Attempt to finish this output stream, writing out final chunks of data. /// /// Note that this function can only be used once data has finished being /// written to the output stream. After this function is called then further /// calls to `write` may result in a panic. /// /// # Panics /// /// Attempts to write data to this stream may result in a panic after this /// function is called. /// /// # Errors /// /// This function will perform I/O to finish the stream, returning any /// errors which happen. pubfn try_finish(&mutself) -> io::Result<()> { self.finish_and_check_crc()?;
Ok(())
}
/// Consumes this decoder, flushing the output stream. /// /// This will flush the underlying data stream and then return the contained /// writer if the flush succeeded. /// /// Note that this function may not be suitable to call in a situation where /// the underlying stream is an asynchronous I/O stream. To finish a stream /// the `try_finish` (or `shutdown`) method should be used instead. To /// re-acquire ownership of a stream it is safe to call this method after /// `try_finish` or `shutdown` has returned `Ok`. /// /// # Errors /// /// This function will perform I/O to complete this stream, and any I/O /// errors which occur will be returned from this function. pubfn finish(mutself) -> io::Result<W> { self.finish_and_check_crc()?;
Ok(self.inner.take_inner().into_inner())
}
let crc = ((self.crc_bytes[0] as u32) << 0)
| ((self.crc_bytes[1] as u32) << 8)
| ((self.crc_bytes[2] as u32) << 16)
| ((self.crc_bytes[3] as u32) << 24); let amt = ((self.crc_bytes[4] as u32) << 0)
| ((self.crc_bytes[5] as u32) << 8)
| ((self.crc_bytes[6] as u32) << 16)
| ((self.crc_bytes[7] as u32) << 24); if crc != self.inner.get_ref().crc().sum() { return Err(corrupt());
} if amt != self.inner.get_ref().crc().amount() { return Err(corrupt());
}
Ok(())
}
}
impl<W: Write> Write for GzDecoder<W> { fn write(&mutself, mut buf: &[u8]) -> io::Result<usize> { let buflen = buf.len(); ifself.header().is_none() { matchself.header_parser.parse(&mut buf) {
Err(err) => { if err.kind() == io::ErrorKind::UnexpectedEof { // all data read but header still not complete
Ok(buflen)
} else {
Err(err)
}
}
Ok(_) => {
debug_assert!(self.header().is_some()); // buf now contains the unread part of the original buf let n = buflen - buf.len();
Ok(n)
}
}
} else { let (n, status) = self.inner.write_with_status(buf)?;
if status == Status::StreamEnd && n < buf.len() && self.crc_bytes.len() < 8 { let remaining = buf.len() - n; let crc_bytes = cmp::min(remaining, CRC_BYTES_LEN - self.crc_bytes.len()); self.crc_bytes.extend(&buf[n..n + crc_bytes]); return Ok(n + crc_bytes);
}
Ok(n)
}
}
/// A gzip streaming decoder that decodes a [gzip file] with multiple members. /// /// This structure exposes a [`Write`] interface that will consume compressed data and /// write uncompressed data to the underlying writer. /// /// A gzip file consists of a series of *members* concatenated one after another. /// `MultiGzDecoder` decodes all members of a file and writes them to the /// underlying writer one after another. /// /// To handle members separately, see [GzDecoder] or read more /// [in the introduction](../index.html#about-multi-member-gzip-files). /// /// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5 #[derive(Debug)] pubstruct MultiGzDecoder<W: Write> {
inner: GzDecoder<W>,
}
impl<W: Write> MultiGzDecoder<W> { /// Creates a new decoder which will write uncompressed data to the stream. /// If the gzip stream contains multiple members all will be decoded. pubfn new(w: W) -> MultiGzDecoder<W> {
MultiGzDecoder {
inner: GzDecoder::new(w),
}
}
/// Returns the header associated with the current member. pubfn header(&self) -> Option<&GzHeader> { self.inner.header()
}
/// Acquires a reference to the underlying writer. pubfn get_ref(&self) -> &W { self.inner.get_ref()
}
/// Acquires a mutable reference to the underlying writer. /// /// Note that mutating the output/input state of the stream may corrupt this /// object, so care must be taken when using this method. pubfn get_mut(&mutself) -> &mut W { self.inner.get_mut()
}
/// Attempt to finish this output stream, writing out final chunks of data. /// /// Note that this function can only be used once data has finished being /// written to the output stream. After this function is called then further /// calls to `write` may result in a panic. /// /// # Panics /// /// Attempts to write data to this stream may result in a panic after this /// function is called. /// /// # Errors /// /// This function will perform I/O to finish the stream, returning any /// errors which happen. pubfn try_finish(&mutself) -> io::Result<()> { self.inner.try_finish()
}
/// Consumes this decoder, flushing the output stream. /// /// This will flush the underlying data stream and then return the contained /// writer if the flush succeeded. /// /// Note that this function may not be suitable to call in a situation where /// the underlying stream is an asynchronous I/O stream. To finish a stream /// the `try_finish` (or `shutdown`) method should be used instead. To /// re-acquire ownership of a stream it is safe to call this method after /// `try_finish` or `shutdown` has returned `Ok`. /// /// # Errors /// /// This function will perform I/O to complete this stream, and any I/O /// errors which occur will be returned from this function. pubfn finish(self) -> io::Result<W> { self.inner.finish()
}
}
impl<W: Write> Write for MultiGzDecoder<W> { fn write(&mutself, buf: &[u8]) -> io::Result<usize> { if buf.is_empty() {
Ok(0)
} else { matchself.inner.write(buf) {
Ok(0) => { // When the GzDecoder indicates that it has finished // create a new GzDecoder to handle additional data. self.inner.try_finish()?; let w = self.inner.inner.take_inner().into_inner(); self.inner = GzDecoder::new(w); self.inner.write(buf)
}
res => res,
}
}
}
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World";
#[test] fn decode_writer_one_chunk() { letmut e = GzEncoder::new(Vec::new(), Compression::default());
e.write(STR.as_ref()).unwrap(); let bytes = e.finish().unwrap();
letmut writer = Vec::new(); letmut decoder = GzDecoder::new(writer); let n = decoder.write(&bytes[..]).unwrap();
decoder.write(&bytes[n..]).unwrap();
decoder.try_finish().unwrap();
writer = decoder.finish().unwrap(); let return_string = String::from_utf8(writer).expect("String parsing error");
assert_eq!(return_string, STR);
}
#[test] fn decode_writer_partial_header() { letmut e = GzEncoder::new(Vec::new(), Compression::default());
e.write(STR.as_ref()).unwrap(); let bytes = e.finish().unwrap();
letmut writer = Vec::new(); letmut decoder = GzDecoder::new(writer);
assert_eq!(decoder.write(&bytes[..5]).unwrap(), 5); let n = decoder.write(&bytes[5..]).unwrap(); if n < bytes.len() - 5 {
decoder.write(&bytes[n + 5..]).unwrap();
}
writer = decoder.finish().unwrap(); let return_string = String::from_utf8(writer).expect("String parsing error");
assert_eq!(return_string, STR);
}
#[test] fn decode_writer_partial_crc() { letmut e = GzEncoder::new(Vec::new(), Compression::default());
e.write(STR.as_ref()).unwrap(); let bytes = e.finish().unwrap();
letmut writer = Vec::new(); letmut decoder = GzDecoder::new(writer); let l = bytes.len() - 5; let n = decoder.write(&bytes[..l]).unwrap();
decoder.write(&bytes[n..]).unwrap();
writer = decoder.finish().unwrap(); let return_string = String::from_utf8(writer).expect("String parsing error");
assert_eq!(return_string, STR);
}
// Two or more gzip files concatenated form a multi-member gzip file. MultiGzDecoder will // concatenate the decoded contents of all members. #[test] fn decode_multi_writer() { letmut e = GzEncoder::new(Vec::new(), Compression::default());
e.write(STR.as_ref()).unwrap(); let bytes = e.finish().unwrap().repeat(2);
letmut writer = Vec::new(); letmut decoder = MultiGzDecoder::new(writer); letmut count = 0; while count < bytes.len() { let n = decoder.write(&bytes[count..]).unwrap();
assert!(n != 0);
count += n;
}
writer = decoder.finish().unwrap(); let return_string = String::from_utf8(writer).expect("String parsing error"); let expected = STR.repeat(2);
assert_eq!(return_string, expected);
}
// GzDecoder consumes one gzip member and then returns 0 for subsequent writes, allowing any // additional data to be consumed by the caller. #[test] fn decode_extra_data() { let compressed = { letmut e = GzEncoder::new(Vec::new(), Compression::default());
e.write(STR.as_ref()).unwrap(); letmut b = e.finish().unwrap();
b.push(b'x');
b
};
letmut writer = Vec::new(); letmut decoder = GzDecoder::new(writer); letmut consumed_bytes = 0; loop { let n = decoder.write(&compressed[consumed_bytes..]).unwrap(); if n == 0 { break;
}
consumed_bytes += n;
}
writer = decoder.finish().unwrap(); let actual = String::from_utf8(writer).expect("String parsing error");
assert_eq!(actual, STR);
assert_eq!(&compressed[consumed_bytes..], b"x");
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-06-21)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.