認識 Compress Stream
.NET Framework 提供二個類別,用來處理壓縮資料。
- GZIP:使用 GZipStream 類別表示 GZIP 資料格式,它無失真檔案壓縮和解壓縮的工業標準演算法。
- Deflate:使用 DeflateStream 類別表示結實 (Deflate) 演算法,該演算法是無失真檔案壓縮和解壓縮的工業標準演算法。它使用 LZ77 演算法和 Huffman編碼的組合。
關於這二個壓縮物件
- 最大只能對4GB的資料進行壓縮。
- GZIP 壓縮後的資料包含一些檔頭資訊,Deflate 則無。
- GZipStream 類別使用 GZIP 資料格式,這種格式包含用於偵測資料損毀的循環冗餘檢查值 (Cyclic Redundancy Check value, CRC)。
- 若要自用的話,使用 DeflateStream 方法會壓的小一些;若要分發出去給其他人使用,則使用 GZipStream 。
.Net4.0已經沒有4G的限制了,另外在 Stream 類別中提供新的 CopyTo 方法,可快速方便複製目前資料流的內容到另一個資料流。
如何壓縮資料流
一般資料流執行寫入動作時,會將資料輸出到某個資源檔中。 例如: FileStream 會輸出到檔案,而 MemoryStream 則是輸出到記憶體。 而壓縮資料流則是輸出另一個資料流 (FileStream、MemoryStrem...)。 所以,當建立 GZipStream 的執行個體時,必須提供一個 Stream 當參數,然後再呼叫執行個體的 GZipStream.Write 方法,資料就會寫入到該 Stream 。
GZipStream 建構子:
//參數 stream //壓縮時,做為輸出的資料流 //解壓縮時,做為來源的資料流 public GZipStream(Stream stream, CompressionMode mode); public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen); //leaveOpen : true 表示在處置 GZipStream 物件之後,將資料流保持開啟,否則為 false。
GZipStream.Write :
Writes compressed bytes to the underlying stream from the specified byte array.
public override void Write( byte[] array, //將 array 中的資料,壓縮之後,寫到執行個體指定的那個 stream。 int offset, int count )
GZipStream.Read :
Reads a number of decompressed bytes into the specified byte array.
public override int Read( byte[] array, //由執行個體指定的那個 stream 讀取資料,解壓縮後,寫到 array 陣列。 int offset, int count )
壓縮資料的簡單步驟:
- 建立一個輸出資料流 Stream ,用來存放壓縮後的資料。
- 建立 GZipStream 物件。指定輸出資料流,並將 CompressionMode 設定為 Compress。
- 讀取資料。
- 將讀取的資料,透過 GZipStream.Write 方法,執行壓縮,並將壓縮過的資料寫入到 Stream 。
public static void GZipCompress1(string inFilename)
{
// 建立一個輸出資料流 Stream ,用來存放壓縮後的資料。
string outFilename = inFilename + ".gz";
FileStream fs_Dest = File.Create(outFilename);
// 建立 GZipStream 物件。指定輸出資料流,並將 CompressionMode 設為 Compress。
GZipStream gzipStream = new GZipStream(fs_Dest, CompressionMode.Compress);
// 讀取來源檔的資料
FileStream fs_Source = File.OpenRead(inFilename);
const int buf_size = 4096;
byte[] buffer = new byte[buf_size];
int bytes_read = 0;
do
{
bytes_read = fs_Source.Read(buffer, 0, buf_size);
//寫入壓縮資料流 compStream
gzipStream.Write(buffer, 0, bytes_read);
} while (bytes_read != 0);
gzipStream.Close();
fs_Dest.Close();
fs_Source.Close();
}
public static void GZipCompress2(string inFilename)
{
// 建立一個輸出資料流 Stream ,用來存放壓縮後的資料。
string outFilename = inFilename + ".gz";
FileStream fs_Dest = File.Create(outFilename);
// 建立 GZipStream 物件。指定輸出資料流,並將 CompressionMode 設為 Compress。
GZipStream compStream = new GZipStream(fs_Dest, CompressionMode.Compress);
// 讀取來源檔的資料
FileStream fs_Source = File.OpenRead(inFilename);
// 將資料由 filestream CopyTo GZipStream 完成壓縮
fs_Source.CopyTo(compStream);
compStream.Close();
fs_Dest.Close();
fs_Source.Close();
}
public static void GZipCompress3(string inFilename)
{
string outFilename = inFilename + ".gz";
// 目的檔
using (FileStream fs_Dest = File.Create(outFilename))
{
// 壓縮資料流
using (GZipStream gzipStream = new GZipStream(fs_Dest, CompressionMode.Compress))
{
// 來源檔
using (FileStream fs_Source = File.OpenRead(inFilename))
{
// 來源檔 -> 壓縮資料流
fs_Source.CopyTo(gzipStream);
fs_Source.Flush();
gzipStream.Flush();
}
}
}
}
如何解壓縮資料流
解壓縮和壓縮的方法大至相同,只是對象不太一樣。
進行壓縮的時候, GZipStream 執行個體所包裹的資料流,是一個空的資料流,目的是要用來存放壓縮後的資料。
進行解壓縮的時候, GZipStream 執行個體所包裹的資料流,是一個包含原壓縮資料的資料流,通常就是指向壓縮檔的檔案資料流。
解壓縮資料的簡單步驟:
- 建立一個資料流 Stream ,包裹要被解壓縮的資料。
- 建立 GZipStream 物件。指定來源資料流,並將 CompressionMode 設定為 Decompress。
- 建立一個 byte[] 的緩衝區,用來暫存解壓縮後的資料。
- 叫用 GZipStream.Read 方法,由 Stream 讀取資料,以執行解壓縮,並將解壓縮的資料存放在步驟3的緩衝區。
// 建立一個 DeflateStream
FileStream fs = new FileStream("testdata.def", FileMode.Open); //開啟 Deflate 格式的壓縮檔
DeflateStream cs = new DeflateStream(fs, CompressionMode.Decompress);
MemoryStream memStream = new MemoryStream();
byte[] buffer = new byte[4096];
int offset = 0;
int count = 0;
while (true)
{
count = cs.Read(buffer, 0, 4096); //讀取解壓縮資料
if (count > 0)
{
memStream.Write(buffer, 0, count); //將 buffer 先丟到 memory stream
offset += count;
}
else
break;
}
byte[] data = memStream.ToArray();
cs.Close();
fs.Close();
string sContent = Encoding.Default.GetString(data);
public static void GZipDecompress2(string inFilename)
{
FileInfo fi = new FileInfo(inFilename);
//取得來源檔的資料流
FileStream fs_Source = fi.OpenRead();
// 建立 GZipStream 物件。指定來源資料流,並將 CompressionMode 設為 Decompress。
GZipStream gzipStream = new GZipStream(fs_Source, CompressionMode.Decompress);
//建立目的檔資料流
string outFilename = inFilename.Remove(inFilename.Length - fi.Extension.Length); //移除壓縮檔副檔名
FileStream fs_Dest = File.Create(outFilename);
// 將資料由 GZipStream CopyTo filestream 完成解壓縮
gzipStream.CopyTo(fs_Dest);
gzipStream.Close();
fs_Source.Close();
fs_Dest.Close();
}
public static void GZipDecompress3(string inFilename)
{
FileInfo fi = new FileInfo(inFilename);
string outFilename = inFilename.Remove(inFilename.Length - fi.Extension.Length); //移除壓縮檔副檔名
// 來源檔
using (FileStream fs_Source = File.OpenRead(inFilename))
{
// 解壓縮資料流
using (GZipStream gzipStream = new GZipStream(fs_Source, CompressionMode.Decompress))
{
// 目的檔
using (FileStream fs_Dest = File.Create(outFilename))
{
// 解壓縮資料流 -> 目的檔
gzipStream.CopyTo(fs_Dest);
fs_Source.Flush();
gzipStream.Flush();
}
}
}
}
範例:利用 MemoryStream 壓縮與解壓縮資料
//=================================================================================
// 產生測試資料
//=================================================================================
StringBuilder tmp = new StringBuilder();
for (int i = 1; i <= 20000; i++)
tmp.AppendLine(i.ToString() + " Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World");
byte[] source_data = Encoding.Default.GetBytes(tmp.ToString());
//=================================================================================
// 壓縮 byte[] 資料至 MemoryStream 中
//=================================================================================
// 建立一個 ZipStream
MemoryStream dest_stream = new MemoryStream();
GZipStream zipStream1 = new GZipStream(dest_stream, CompressionMode.Compress);
// 輸出壓縮資料
zipStream1.Write(source_data, 0, source_data.Length);
zipStream1.Close();
// 將 MemoryStream 裡的資料轉到 byte[]
byte[] compress_data = dest_stream.ToArray();
//=================================================================================
// 將資料載入到 MemoryStream 中,再解壓縮
//=================================================================================
// 將資料載入到 MemoryStream 中
MemoryStream source_stream = new MemoryStream(compress_data);
// 建立一個 ZipStream
GZipStream zipStream2 = new GZipStream(source_stream, CompressionMode.Decompress);
// 輸出解壓縮後資料
MemoryStream tmpMemoryStream = new MemoryStream();
int theByte = zipStream1.ReadByte();
while (theByte != -1)
{
tmpMemoryStream.WriteByte((byte)theByte);
theByte = zipStream2.ReadByte();
}
// 將 tmpMemoryStream 裡的資料轉到 byte[]
byte[] decompress_data = tmpMemoryStream.ToArray();
zipStream2.Close();
string sContent = Encoding.Default.GetString(decompress_data);
沒有留言:
張貼留言