1. 程式人生 > >C# 用GZipStream 壓縮流來壓縮和解壓檔案

C# 用GZipStream 壓縮流來壓縮和解壓檔案

最近在用c#做一些工作,其中需要把檔案進行壓縮和解壓。
有很多種方法,其中比較成熟的就是用別人的類。
可以參考部落格c#壓縮檔案

比較簡單的方式就是用流壓縮,將要寫入的資料變成位元組型陣列,直接寫入流中即可。

程式碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using
System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace 檔案流 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string s = "壓縮檔案實驗"; SaveFileDialog sf = new SaveFileDialog() { //設定檔案儲存型別
Filter = "zif檔案|*.zif|所有檔案|*.*", //如果使用者沒有輸入副檔名,自動追加字尾 AddExtension = true, //設定標題 Title = "存檔案", //設定預設檔案型別顯示順序 FilterIndex = 1, //儲存對話方塊是否記憶上次開啟的目錄 RestoreDirectory = true
}; //如果使用者點選了儲存按鈕 if (sf.ShowDialog() == DialogResult.OK) { //例項化一個檔案流--->與寫入檔案相關聯 FileStream fs = new FileStream(sf.FileName, FileMode.Create); //將字串轉成位元組陣列 var bytes = System.Text.Encoding.Default.GetBytes(s); //開始寫入(直接寫入檔案了) //fs.Write(bytes , 0, bytes .Length); using (GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress)) //代開壓縮檔案流 { zipStream.Write(bytes, 0, bytes.Length); //寫入壓縮檔案 MessageBox.Show("壓縮成功!"); } } } //解壓寫的不好 private void button2_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog() { Filter = "壓縮 files (*.zif)|*.zif|All files (*.*)|*.*"//檔案過濾選擇 }; if (ofd.ShowDialog() == DialogResult.OK) { using (FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read)) { using (GZipStream zipStream = new GZipStream(fs, CompressionMode.Decompress)) { int bytesRead; byte[] bytes = new byte[1024*1024*4]; //超大陣列,先把資料全部複製出來。 while ((bytesRead = zipStream.Read(bytes, 0, bytes.Length)) > 0)//bytetesRead是讀出來的位元組數 { try { byte[] longbindata = new byte[bytesRead]; Array.Copy(bytes, 0, longbindata, 0, bytesRead); System.Diagnostics.Trace.WriteLine(longbindata[0].ToString()); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message); } } MessageBox.Show("解壓成功!"); //} } } } } }

上次那個解壓操作需要設定一個超大陣列,這簡直就是不人性化呀,查詢了很久,找到另外一種方法:
第一個函式,將流轉成位元組陣列:

        public byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 設定當前流的位置為流的開始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

第二個函式,將流轉成的位元組陣列傳入以下函式,則可以返回解壓之後的位元組陣列:

        public static byte[] Decompress(byte[] bytes)
        {
            using (var compressStream = new MemoryStream(bytes))
            {
                using (var zipStream = new GZipStream(compressStream, CompressionMode.Decompress))
                {
                    using (var resultStream = new MemoryStream())
                    {
                        zipStream.CopyTo(resultStream);
                        return resultStream.ToArray();
                    }
                }
            }
        }

所以解壓過程就很人性化:data即是所需要的陣列。

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog()
            {
                Filter = "壓縮 files (*.zif)|*.zif|All files (*.*)|*.*"//檔案過濾選擇
            };

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                byte[] data = null;            
                using (FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read))
                {
                    data = StreamToBytes(fs);
                    data = Decompress(data);
                }
            }
        }