在.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)編寫),希望你喜歡.謝謝!
本文配套源碼