由於它看起來像活潑的需要一次壓縮所有,你只需要緩衝一切,直到結束。然後,您可以刷新,並在年底壓縮:
use std::io::{self, Write, Cursor};
fn compress(_data: &[u8]) -> Vec<u8> {
// The best compression ever
b"compressed".as_ref().into()
}
struct SnappyCompressor<W> {
inner: W,
buffer: Vec<u8>,
}
impl<W> SnappyCompressor<W>
where W: Write
{
fn new(inner: W) -> Self {
SnappyCompressor {
inner: inner,
buffer: vec![],
}
}
}
impl<W> Write for SnappyCompressor<W>
where W: Write
{
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
self.buffer.extend(data);
Ok(data.len())
}
fn flush(&mut self) -> io::Result<()> {
let compressed = compress(&self.buffer);
self.inner.write_all(&compressed)
}
}
fn main() {
let mut output = Cursor::new(vec![]);
{
let mut compressor = SnappyCompressor::new(output.by_ref());
assert_eq!(5, compressor.write(b"hello").unwrap());
assert_eq!(5, compressor.write(b"world").unwrap());
compressor.flush().unwrap();
}
let bytes = output.into_inner();
assert_eq!(&b"compressed"[..], &bytes[..]);
}
這個解決方案有一個很大的疑問的方面 - 我們正在使用flush
標記流的結束,但是這不是真的那麼方法的意義。使用純流式壓縮機可能會好得多,但有時你必須做你必須做的事情。
還有幾個地雷:
- 你必須顯式調用
flush
- 你不能叫
flush
兩次。
要允許用戶簡單地丟棄壓縮機並讓它來完成,可以實現Drop
:
impl<W> Drop for SnappyCompressor<W>
where W: Write
{
fn drop(&mut self) {
self.flush().unwrap();
}
}
爲了防止企圖沖洗兩次,你需要添加一個標誌來跟蹤:
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if self.is_flushed {
return Err(Error::new(ErrorKind::Other, "Buffer has already been compressed, cannot add more data"));
}
self.buffer.extend(data);
Ok(data.len())
}
fn flush(&mut self) -> io::Result<()> {
if self.is_flushed {
return Ok(())
}
self.is_flushed = true;
let compressed = compress(&self.buffer);
self.inner.write_all(&compressed)
}
總之,最後的版本是這樣的:
use std::io::{self, Write, Cursor, Error, ErrorKind};
fn compress(_data: &[u8]) -> Vec<u8> {
// The best compression ever
b"compressed".as_ref().into()
}
struct SnappyCompressor<W>
where W: Write
{
inner: W,
buffer: Vec<u8>,
is_flushed: bool,
}
impl<W> SnappyCompressor<W>
where W: Write
{
fn new(inner: W) -> Self {
SnappyCompressor {
inner: inner,
buffer: vec![],
is_flushed: false,
}
}
// fn into_inner
}
impl<W> Write for SnappyCompressor<W>
where W: Write
{
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if self.is_flushed {
return Err(Error::new(ErrorKind::Other, "Buffer has already been compressed, cannot add more data"));
}
self.buffer.extend(data);
Ok(data.len())
}
fn flush(&mut self) -> io::Result<()> {
if self.is_flushed {
return Ok(())
}
self.is_flushed = true;
let compressed = compress(&self.buffer);
self.inner.write_all(&compressed)
}
}
impl<W> Drop for SnappyCompressor<W>
where W: Write
{
fn drop(&mut self) {
self.flush().unwrap();
}
}
fn main() {
let mut output = Cursor::new(vec![]);
{
let mut compressor = SnappyCompressor::new(output.by_ref());
assert_eq!(5, compressor.write(b"hello").unwrap());
assert_eq!(5, compressor.write(b"world").unwrap());
compressor.flush().unwrap();
}
let bytes = output.into_inner();
assert_eq!(&b"compressed"[..], &bytes[..]);
}
快速兼容壓縮多個緩衝區,然後將它們一起打包?函數簽名似乎表明它期望一次壓縮和解壓縮所有內容。如果是這樣的話,你需要將所有內容都緩存起來(寫入'Vec'),最後壓縮一切。 –
Shepmaster
你說得對。我最初認爲,因爲我知道未壓縮的大小將是不變的,我也可以分開緩衝區並逐個解壓縮它們。但知道未壓縮的大小不會幫助我,因爲壓縮後的大小不會是恆定的。 我會嘗試使用'Vec,u8>',看看它是如何影響性能的。謝謝。 另外,我應該如何處理這個問題stackoverflow明智?我應該刪除它嗎,還是有一種方法可以在未選擇答案的情況下將其標記爲已解決? –
我認爲你問這個問題的方式有一個答案,所以我會在接下來的一兩個小時內發佈我的答案。答案只是不會做你想要的:-) – Shepmaster