工作上有愈來愈多需要加密壓縮的場合,過去我慣用的做法是從 C# 呼叫外部程式,借助 7z.exe 完成任務。不方便之處是我必須先將要打包加密的內容依目錄結構寫成暫存檔,再交給 7-Zip 處理,且做完必須刪檔抹去足跡。這裡隱藏一個危機,若程式在寫暫存檔到刪檔前出錯,便可能殘留明文內容,有資訊外流風險。因此,讓加密壓縮過程完全在記憶體裡完成是較完美的做法。

過去我有示範過用 .NET 4.5 的 ZipArchive、ZipFile 實現 byte[] 不落地壓縮 ZIP 檔,可惜它無法支援加密。放心,.NET 開發社群是很強大的,你想得到的需求幾乎都有解決方案。

針對本次的需求,免費的 DotNetZip Library 開源專案是個好選擇,用 NuGet 即可下載:

DotNetZip 的使用方法十分簡便,現場來個簡單範例。我打算用 C# 動態產一個 Secret.zip 檔案提供本日業績資料,其中包含兩個檔案,index.html 與 imgs\chart.png,ZIP 檔需以密碼加密。這個範例涵蓋了輸出 string 到文字檔、輸出 byte[] 到圖檔、區分資料夾結構、使用密碼加密等功能。

程式碼如下:(我還很無聊地用 Graphics 胡亂畫出長條圖 .png 練手感)

using Ionic.Zip;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var zip = new ZipFile())
            {
                zip.Password = "P@ssW0rd";
                zip.AddEntry("imgs\\chart.png", GenChart());
                zip.AddEntry("index.html", $@"
<html><body>
    <div>{DateTime.Today:yyyy-MM-dd} 業績</div>
    <img src='imgs/chart.png' />
</body>");
                zip.Save("D:\\Secret.zip");
            }
        }

        static byte[] GenChart()
        {
            var bmp = new Bitmap(240, 180);
            var g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.LightGray),
                0, 0, bmp.Width, bmp.Height);
            var p = new Pen(new SolidBrush(Color.Black));
            var margin = 6;
            g.DrawRectangle(p, margin, margin, 1, bmp.Height - margin * 2);
            g.DrawRectangle(p, margin, bmp.Height - margin, bmp.Width - margin * 2, 1);
            var colors = new Color[]
            {
                Color.Green,
                Color.Brown,
                Color.BlueViolet,
                Color.Indigo
            };
            var barAreaWidth = (bmp.Width - margin * 2) / 4;
            var barWidth = 40;
            var rnd = new Random();
            Enumerable.Range(0, 4).ToList()
                .ForEach(i =>
                {
                    var value = rnd.Next(120) + 50;
                    g.FillRectangle(new SolidBrush(colors[i]), 
                        margin + i * barAreaWidth + (barAreaWidth - barWidth) / 2, 
                        bmp.Height - margin - value, 
                        barWidth, 
                        value);
                });
            using (var ms = new MemoryStream())
            {
                bmp.Save(ms, ImageFormat.Png);
                return ms.ToArray();
            }
        }
    }
}

如此,我們成功的產生加密 ZIP 檔,具備資料夾結構,過程沒產生任何暫存檔。

網頁內容檢視正常,大成功!

Example of using DotNetZip to compress data in memory to encrypted zip file


Comments

# by Bryan

7-zip 其實有 c# 的 sdk 叫 lzma sdk,請見網址 https://www.7-zip.org/sdk.html

# by Jeffrey

to Bryan,哦哦哦,好物! 感謝分享,有空來研究一下。

Post a comment


64 - 11 =