專案需打包下載功能,採用開源 ICSharpCode SharpZipLib 實作 Zip 壓縮,支援多檔案、自訂目錄結構、密碼保護、壓縮等級。
ZipOutputStream 逐一寫入 ZipEntry,保留相對路徑結構。private bool Zip(string zipPath, string topDir, int level, string password, string[] paths) {
var allFiles = new List<string>();
foreach (var p in paths) {
if (File.Exists(p)) allFiles.Add(p);
else if (Directory.Exists(p)) GetDirectoryFiles(p, allFiles);
}
if (allFiles.Count == 0) return false;
using (var zip = new ZipOutputStream(File.Create(zipPath))) {
zip.SetLevel(level); zip.Password = password;
foreach (var file in allFiles) {
var entryName = file.Replace(topDir, "").TrimStart('\\');
var entry = new ZipEntry(entryName) { DateTime = DateTime.Now };
zip.PutNextEntry(entry);
if (!file.EndsWith("\\")) { // 檔案
using (var fs = File.OpenRead(file)) {
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
zip.Write(buffer, 0, buffer.Length);
}
}
}
zip.Finish();
}
return true;
}
private void GetDirectoryFiles(string dir, List<string> list) {
list.AddRange(Directory.GetFiles(dir));
foreach (var d in Directory.GetDirectories(dir)) GetDirectoryFiles(d, list);
if (Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0)
list.Add(dir); // 空目錄
}
原版一次讀入整檔案記憶體壓力大,改為迴圈分段讀寫:
using (var fs = File.OpenRead(file)) {
for (long offset = 0; offset < fs.Length; offset += 65536) {
int len = (int)Math.Min(65536, fs.Length - offset);
byte[] buffer = new byte[len];
fs.Read(buffer, 0, len);
zip.Write(buffer, 0, len);
}
}
Zip(@"C:\Task1\ZipTest.zip", @"C:\Task1\", 6, "",
new[] { @"C:\Task1\zipdemo\11\", @"C:\Task1\zipdemo\Bin\ICSharpCode.SharpZipLib.dll" });
程式碼參考網路資源整理,歡迎自由使用。