在.Net Framework 2.0 中添加了System.IO.Compression 類來實現對文件的壓縮/解壓(GZipStream方 法),下面我們來看一個簡單的例子.
Code1:
1 public static void Compress(string filePath, string zipPath)
2 {
3 FileStream sourceFile = File.OpenRead(filePath);
4 FileStream destinationFile = File.Create(zipPath);
5 byte[] buffer = new byte[sourceFile.Length];
6 GZipStream zip = null;
7 try
8 {
9 sourceFile.Read(buffer, 0, buffer.Length);
10 zip = new GZipStream(destinationFile, CompressionMode.Compress);
11 zip.Write(buffer, 0, buffer.Length);
12 }
13 catch
14 {
15 throw;
16 }
17 finally
18 {
19 zip.Close();
20 sourceFile.Close();
21 destinationFile.Close();
22 }
23 }
24
25 public static void Decompress(string zipPath,string filePath)
26 {
27 FileStream sourceFile = File.OpenRead(zipPath);
28
29 string path = filePath.Replace(Path.GetFileName(filePath), "");
30
31 if(!Directory.Exists(path))
32 Directory.CreateDirectory(path);
33
34 FileStream destinationFile = File.Create(filePath);
35 GZipStream unzip = null;
36 byte[] buffer = new byte[sourceFile.Length];
37 try
38 {
39 unzip = new GZipStream(sourceFile, CompressionMode.Decompress,
true);
40 int numberOfBytes = unzip.Read(buffer, 0, buffer.Length);
41
42 destinationFile.Write(buffer, 0, numberOfBytes);
43 }
44 catch
45 {
46 throw;
47 }
48 finally
49 {
50 sourceFile.Close();
51 destinationFile.Close();
52 unzip.Close();
53 }
54 }
用例:
1.壓縮
1 string folder = Path.Combine(Server.MapPath("~"), "TestCompress");
2 string file = "file1.txt";
3 string zip = "myzip";
4
5 SampleCompress.Compress(Path.Combine(folder, file), Path.Combine(folder,
zip));
2.解壓
1 string folder = Path.Combine(Server.MapPath("~"), "TestCompress");
Path.Combine
(Path.Combine(folder, "zipfolder"), file));
2 string file = "file1.txt";
3 string zip = "myzip";
4
5 SampleCompress.Decompress(Path.Combine(folder, zip),
由代碼和使用例子我們可以了解到,Code1 只是支持單個文本文件的壓縮/解壓, 代碼非常簡單,但是卻 實際上卻沒什麼用途,功能太少,只是讓你有個初步的認識.下面介紹Code2來實現本文的主題內容.
Code2:
public class GZip { /// <summary> /// Compress /// </summary> /// <param name="lpSourceFolder">The location of the files to include in the zip file, all files including files in subfolders will be included.</param> /// <param name="lpDestFolder">Folder to write the zip file into</param> /// <param name="zipFileName">Name of the zip file to write</param> public static GZipResult Compress(string lpSourceFolder, string lpDestFolder, string zipFileName) { return Compress(lpSourceFolder, "*.*", SearchOption.AllDirectories, lpDestFolder, zipFileName, true); } /// <summary> /// Compress /// </summary> /// <param name="lpSourceFolder">The location of the files to include in the zip file</param> /// <param name="searchPattern">Search pattern (ie "*.*" or "*.txt" or "*.gif") to idendify what files in lpSourceFolder to include in the zip file</param> /// <param name="searchOption">Only files in lpSourceFolder or include files in subfolders also</param> /// <param name="lpDestFolder">Folder to write the zip file into</param> /// <param name="zipFileName">Name of the zip file to write</param> /// <param name="deleteTempFile">Boolean, true deleted the intermediate temp file, false leaves the temp file in lpDestFolder (for debugging) </param> public static GZipResult Compress(string lpSourceFolder, string searchPattern, SearchOption searchOption, string lpDestFolder, string zipFileName, bool deleteTempFile) { DirectoryInfo di = new DirectoryInfo(lpSourceFolder); FileInfo[] files = di.GetFiles("*.*", searchOption); return Compress(files, lpSourceFolder, lpDestFolder, zipFileName, deleteTempFile); } /// <summary> /// Compress /// </summary> /// <param name="files">Array of FileInfo objects to be included in the zip file</param> /// <param name="folders">Array of Folder string</param> /// <param name="lpBaseFolder">Base folder to use when creating relative paths for the files /// stored in the zip file. For example, if lpBaseFolder is 'C:\zipTest\Files\', and there is a file /// 'C:\zipTest\Files\folder1\sample.txt' in the 'files' array, the relative path for sample.txt /// will be 'folder1/sample.txt'</param> /// <param name="lpDestFolder">Folder to write the zip file into</param> /// <param name="zipFileName">Name of the zip file to write</param> public static GZipResult Compress(FileInfo[] files, string[] folders, string lpBaseFolder, string lpDestFolder, string zipFileName) { //support compress folder IList<FileInfo> list = new List<FileInfo>(); foreach (FileInfo li in files) list.Add(li); foreach (string str in folders) { DirectoryInfo di = new DirectoryInfo(str); foreach (FileInfo info in di.GetFiles("*.*", SearchOption.AllDirectories)) { list.Add(info); } } return Compress(list.ToArray(), lpBaseFolder, lpDestFolder, zipFileName, true); } /// <summary> /// Compress /// </summary> /// <param name="files">Array of FileInfo objects to be included in the zip file</param> /// <param name="lpBaseFolder">Base folder to use when creating relative paths for the files /// stored in the zip file. For example, if lpBaseFolder is 'C:\zipTest\Files\', and there is a file /// 'C:\zipTest\Files\folder1\sample.txt' in the 'files' array, the relative path for sample.txt /// will be 'folder1/sample.txt'</param> /// <param name="lpDestFolder">Folder to write the zip file into</param> /// <param name="zipFileName">Name of the zip file to write</param> public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName) { return Compress(files, lpBaseFolder, lpDestFolder, zipFileName, true); } /// <summary> /// Compress /// </summary> /// <param name="files">Array of FileInfo objects to be included in the zip file</param> /// <param name="lpBaseFolder">Base folder to use when creating relative paths for the files /// stored in the zip file. For example, if lpBaseFolder is 'C:\zipTest\Files\', and there is a file /// 'C:\zipTest\Files\folder1\sample.txt' in the 'files' array, the relative path for sample.txt /// will be 'folder1/sample.txt'</param> /// <param name="lpDestFolder">Folder to write the zip file into</param> /// <param name="zipFileName">Name of the zip file to write</param> /// <param name="deleteTempFile">Boolean, true deleted the intermediate temp file, false leaves the temp file in lpDestFolder (for debugging) </param> public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName, bool deleteTempFile) { GZipResult result = new GZipResult(); try { if (!lpDestFolder.EndsWith("\\")) { lpDestFolder += "\\"; } string lpTempFile = lpDestFolder + zipFileName + ".tmp"; string lpZipFile = lpDestFolder + zipFileName; result.TempFile = lpTempFile; result.ZipFile = lpZipFile; if (files != null && files.Length > 0) { CreateTempFile(files, lpBaseFolder, lpTempFile, result); if (result.FileCount > 0) { CreateZipFile(lpTempFile, lpZipFile, result); } // delete the temp file if (deleteTempFile) { File.Delete(lpTempFile); result.TempFileDeleted = true; } } } catch //(Exception ex4) { result.Errors = true; } return result; } private static void CreateZipFile(string lpSourceFile, string lpZipFile, GZipResult result) { byte[] buffer; int count = 0; FileStream fsOut = null; FileStream fsIn = null; GZipStream gzip = null; // compress the file into the zip file try { fsOut = new FileStream(lpZipFile, FileMode.Create, FileAccess.Write, FileShare.None); gzip = new GZipStream(fsOut, CompressionMode.Compress, true); fsIn = new FileStream(lpSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read); buffer = new byte[fsIn.Length]; count = fsIn.Read(buffer, 0, buffer.Length); fsIn.Close(); fsIn = null; // compress to the zip file gzip.Write(buffer, 0, buffer.Length); result.ZipFileSize = fsOut.Length; result.CompressionPercent = GetCompressionPercent(result.TempFileSize, result.ZipFileSize); } catch //(Exception ex1) { result.Errors = true; } finally { if (gzip != null) { gzip.Close(); gzip = null; } if (fsOut != null) { fsOut.Close(); fsOut = null; } if (fsIn != null) { fsIn.Close(); fsIn = null; } } } private static void CreateTempFile(FileInfo[] files, string lpBaseFolder, string lpTempFile, GZipResult result) { byte[] buffer; int count = 0; byte[] header; string fileHeader = null; string fileModDate = null; string lpFolder = null; int fileIndex = 0; string lpSourceFile = null; string vpSourceFile = null; GZipFileInfo gzf = null; FileStream fsOut = null; FileStream fsIn = null; if (files != null && files.Length > 0) { try { result.Files = new GZipFileInfo[files.Length]; // open the temp file for writing fsOut = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None); foreach (FileInfo fi in files) { lpFolder = fi.DirectoryName + "\\"; try { gzf = new GZipFileInfo(); gzf.Index = fileIndex; // read the source file, get its virtual path within the source folder lpSourceFile = fi.FullName; gzf.LocalPath = lpSourceFile; vpSourceFile = lpSourceFile.Replace(lpBaseFolder, string.Empty); vpSourceFile = vpSourceFile.Replace("\\", "/"); gzf.RelativePath = vpSourceFile; fsIn = new FileStream(lpSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read); buffer = new byte[fsIn.Length]; count = fsIn.Read(buffer, 0, buffer.Length); fsIn.Close(); fsIn = null; fileModDate = fi.LastWriteTimeUtc.ToString(); gzf.ModifiedDate = fi.LastWriteTimeUtc; gzf.Length = buffer.Length; fileHeader = fileIndex.ToString() + "," + vpSourceFile + "," + fileModDate + "," + buffer.Length.ToString() + "\n"; header = Encoding.Default.GetBytes(fileHeader); fsOut.Write(header, 0, header.Length); fsOut.Write(buffer, 0, buffer.Length); fsOut.WriteByte(10); // linefeed gzf.AddedToTempFile = true; // update the result object result.Files[fileIndex] = gzf; // increment the fileIndex fileIndex++; } catch //(Exception ex1) { result.Errors = true; } finally { if (fsIn != null) { fsIn.Close(); fsIn = null; } } if (fsOut != null) { result.TempFileSize = fsOut.Length; } } } catch //(Exception ex2) { result.Errors = true; } finally { if (fsOut != null) { fsOut.Close(); fsOut = null; } } } result.FileCount = fileIndex; } public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName) { return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, true, null, null, 4096); } public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName, bool writeFiles, string addExtension) { return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, writeFiles, addExtension, null, 4096); } public static GZipResult Decompress(string lpSrcFolder, string lpDestFolder, string zipFileName, bool deleteTempFile, bool writeFiles, string addExtension, Hashtable htFiles, int bufferSize) { GZipResult result = new GZipResult(); if (!lpSrcFolder.EndsWith("\\")) { lpSrcFolder += "\\"; } if (!lpDestFolder.EndsWith("\\")) { lpDestFolder += "\\"; } string lpTempFile = lpSrcFolder + zipFileName + ".tmp"; string lpZipFile = lpSrcFolder + zipFileName; result.TempFile = lpTempFile; result.ZipFile = lpZipFile; string line = null; string lpFilePath = null; string lpFolder = null; GZipFileInfo gzf = null; FileStream fsTemp = null; ArrayList gzfs = new ArrayList(); bool write = false; if (string.IsNullOrEmpty(addExtension)) { addExtension = string.Empty; } else if (!addExtension.StartsWith(".")) { addExtension = "." + addExtension; } // extract the files from the temp file try { fsTemp = UnzipToTempFile(lpZipFile, lpTempFile, result); if (fsTemp != null) { while (fsTemp.Position != fsTemp.Length) { line = null; while (string.IsNullOrEmpty(line) && fsTemp.Position != fsTemp.Length) { line = ReadLine(fsTemp); } if (!string.IsNullOrEmpty(line)) { gzf = new GZipFileInfo(); if (gzf.ParseFileInfo(line) && gzf.Length > 0) { gzfs.Add(gzf); lpFilePath = lpDestFolder + gzf.RelativePath; lpFolder = GetFolder(lpFilePath); gzf.LocalPath = lpFilePath; write = false; if (htFiles == null || htFiles.ContainsKey (gzf.RelativePath)) { gzf.RestoreRequested = true; write = writeFiles; } if (write) { // make sure the folder exists if (!Directory.Exists(lpFolder)) { Directory.CreateDirectory(lpFolder); } // read from fsTemp and write out the file gzf.Restored = WriteFile(fsTemp, gzf.Length, lpFilePath + addExtension, bufferSize); } else { // need to advance fsTemp fsTemp.Position += gzf.Length; } } } } } } catch //(Exception ex3) { result.Errors = true; } finally { if (fsTemp != null) { fsTemp.Close(); fsTemp = null; } } // delete the temp file try { if (deleteTempFile) { File.Delete(lpTempFile); result.TempFileDeleted = true; } } catch //(Exception ex4) { result.Errors = true; } result.FileCount = gzfs.Count; result.Files = new GZipFileInfo[gzfs.Count]; gzfs.CopyTo(result.Files); return result; } private static string ReadLine(FileStream fs) { string line = string.Empty; const int bufferSize = 4096; byte[] buffer = new byte[bufferSize]; byte b = 0; byte lf = 10; int i = 0; while (b != lf) { b = (byte)fs.ReadByte(); buffer[i] = b; i++; } line = System.Text.Encoding.Default.GetString(buffer, 0, i - 1); return line; } private static bool WriteFile(FileStream fs, int fileLength, string lpFile, int bufferSize) { bool success = false; FileStream fsFile = null; if (bufferSize == 0 || fileLength < bufferSize) { bufferSize = fileLength; } int count = 0; int remaining = fileLength; int readSize = 0; try { byte[] buffer = new byte[bufferSize]; fsFile = new FileStream(lpFile, FileMode.Create, FileAccess.Write, FileShare.None); while (remaining > 0) { if (remaining > bufferSize) { readSize = bufferSize; } else { readSize = remaining; } count = fs.Read(buffer, 0, readSize); remaining -= count; if (count == 0) { break; } fsFile.Write(buffer, 0, count); fsFile.Flush(); } fsFile.Flush(); fsFile.Close(); fsFile = null; success = true; } catch //(Exception ex2) { success = false; } finally { if (fsFile != null) { fsFile.Flush(); fsFile.Close(); fsFile = null; } } return success; } private static string GetFolder(string lpFilePath) { string lpFolder = lpFilePath; int index = lpFolder.LastIndexOf("\\"); if (index != -1) { lpFolder = lpFolder.Substring(0, index + 1); } return lpFolder; } private static FileStream UnzipToTempFile(string lpZipFile, string lpTempFile, GZipResult result) { FileStream fsIn = null; GZipStream gzip = null; FileStream fsOut = null; FileStream fsTemp = null; const int bufferSize = 4096; byte[] buffer = new byte[bufferSize]; int count = 0; try { fsIn = new FileStream(lpZipFile, FileMode.Open, FileAccess.Read, FileShare.Read); result.ZipFileSize = fsIn.Length; fsOut = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None); gzip = new GZipStream(fsIn, CompressionMode.Decompress, true); while (true) { count = gzip.Read(buffer, 0, bufferSize); if (count != 0) { fsOut.Write(buffer, 0, count); } if (count != bufferSize) { break; } } } catch //(Exception ex1) { result.Errors = true; } finally { if (gzip != null) { gzip.Close(); gzip = null; } if (fsOut != null) { fsOut.Close(); fsOut = null; } if (fsIn != null) { fsIn.Close(); fsIn = null; } } fsTemp = new FileStream(lpTempFile, FileMode.Open, FileAccess.Read, FileShare.None); if (fsTemp != null) { result.TempFileSize = fsTemp.Length; } return fsTemp; } private static int GetCompressionPercent(long tempLen, long zipLen) { double tmp = (double)tempLen; double zip = (double)zipLen; double hundred = 100; double ratio = (tmp - zip) / tmp; double pcnt = ratio * hundred; return (int)pcnt; } } public class GZipFileInfo { public int Index = 0; public string RelativePath = null; public DateTime ModifiedDate; public int Length = 0; public bool AddedToTempFile = false; public bool RestoreRequested = false; public bool Restored = false; public string LocalPath = null; public string Folder = null; public bool ParseFileInfo(string fileInfo) { bool success = false; try { if (!string.IsNullOrEmpty(fileInfo)) { // get the file information string[] info = fileInfo.Split(','); if (info != null && info.Length == 4) { this.Index = Convert.ToInt32(info[0]); this.RelativePath = info[1].Replace("/", "\\"); this.ModifiedDate = Convert.ToDateTime(info[2]); this.Length = Convert.ToInt32(info[3]); success = true; } } } catch { success = false; } return success; } } public class GZipResult { public GZipFileInfo[] Files = null; public int FileCount = 0; public long TempFileSize = 0; public long ZipFileSize = 0; public int CompressionPercent = 0; public string TempFile = null; public string ZipFile = null; public bool TempFileDeleted = false; public bool Errors = false; }
用例:
1,壓縮
1 string folder = Path.Combine(Server.MapPath("~"), "TestCompress");
2 FileInfo[] info = { new FileInfo(Path.Combine(folder, "file2.ppt")),
new FileInfo(Path.Combine(folder,"file3.doc")) };
3 GZip.Compress(info, new string[] { Path.Combine(folder, "img") }, folder, folder, "myzip2.zip");
2,解壓
1 string folder = Path.Combine(Server.MapPath("~"), "TestCompress");
2 GZip.Decompress(folder, Path.Combine(folder,"newfolder"),
"myzip2.zip");
Code2代碼很長,但是卻很好用,在上面用例中我對兩個文件和一個文件夾壓縮,壓縮後保存 到"myzip2.zip"文件中,這只是其中一個重載的版本,原代碼來源於http://www.vwd- cms.com/Forum/Forums.aspx?topic=18 ,可惜作者在網上給出的代碼Bug很多,無法正常運行,不過作者的 辛勞還是值得稱贊的.修改後(Code2)已經可以很好的使用了,並增加了壓縮方法的重載.支持多種多個文件 /文件夾的壓縮和解壓還原(支持中文).下面簡單介紹下工作原理:讀取多文件,格式化後,按照某種規則保 存到一個文件中(上面用例保存到myzip2.gzip文件中)
----------------------------------------------------
0,/file2.ppt,2009-2-5 1:52:07,9216
//.....格式化後內容...//
1,/file3.doc,2009-2-5 1:14:54,24064
//.....格式化後內容...//
2,/img/file4.gif,2009-2-3 0:53:47,729
//.....格式化後內容...//
----------------------------------------------------
在整個過程中是通過創建一個臨時文件來處理,解壓中也根據上面內容格式來進行.當然由於這種獨特 的格式,是不支持rar/zip來解壓的.
最後,提供代碼和例子(VS2008開發,.Net Framework 3.5(C Sharp)編寫),希望你喜歡.謝謝!
本文配套源碼