如何压缩多个文件/文件夹(GZipStream and C#)

注意:是GZIP

.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");
2            string file = "file1.txt";//需要压缩的文件
3            string zip = "myzip";//保存文件名
4            //解压
5            SampleCompress.Decompress(Path.Combine(folder, zip),
 Path.Combine(Path.Combine(folder, 
"zipfolder"), file));

 

由代码和使用例子我们可以了解到,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, truetruenullnull4096);
        }

        
public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName, bool writeFiles, string addExtension)
        {
            
return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, writeFiles, addExtension, null4096);
        }

        
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")) }
;//获取两个文件FileInfo("file2.ppt","file3.doc")
3         //其中一个重载版本,压缩两个文件和一个目录("img"文件夹),保存为("myzip2.gzip")
            GZip.Compress(info, 
new string[] { Path.Combine(folder, "img") }, folder, folder, "myzip2.gzip");

 

2,解压

 

1        string folder = Path.Combine(Server.MapPath("~"), "TestCompress");
2        GZip.Decompress(folder, Path.Combine(folder,"newfolder"), "myzip2.gzip");//解压到("newfolder"文件夹)

 

Code2代码很长,但是却很好用,在上面用例中我对两个文件和一个文件夹压缩,压缩后保存到"myzip2.gzip"文件中,这只是其中一个重载的版本,原代码来源于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)编写),希望你喜欢.谢谢!

以上有word 文档直接粘贴,排版可能不太好看,你可以通过下面来下载相应的代码/文档

1,文档

2,原代码

3,用例

文章为原创,如果需要引用,请保留原地址. 有什么问题/错误的地方请联系 fox7805034 (at) hotmail.com

posted @ 2010-09-24 11:06  春哥也编程  阅读(4094)  评论(1编辑  收藏  举报