本文转自博客园:http://www.cnblogs.com/leiOOlei/archive/2011/06/15/2081514.html
关于GZipStream压缩解压,网上找了很多资料,完整的不多,要么是针对字符串压缩解压缩的,要么只实现了针对单个文件的压缩解压缩,还有的不支持子文件夹的压缩,实用性都不是很大。
以下整理了压缩解压缩的代码,供以后拿出来翻阅,在项目中可以直接使用这3个类,已通过测试。
1.首先是有一个描述要压缩的文件类GZipFileInfo,包含了一些文件信息
///<summary>
/// 要压缩的文件信息
///</summary>
publicclass GZipFileInfo
{
///<summary>
/// 文件索引
///</summary>
publicint Index =0;
///<summary>
/// 文件相对路径,'/'
///</summary>
publicstring RelativePath =null;
public DateTime ModifiedDate;
///<summary>
/// 文件内容长度
///</summary>
publicint Length =0;
publicbool AddedToTempFile =false;
publicbool RestoreRequested =false;
publicbool Restored =false;
///<summary>
/// 文件绝对路径,'\'
///</summary>
publicstring LocalPath =null;
publicstring Folder =null;
publicbool 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;
}
}
2.压缩后生成的压缩包信息GZipResult,描述了压缩包的一些属性,包括大小,文件数,以及其中的每一个文件
///<summary>
/// 文件压缩后的压缩包类
///</summary>
publicclass GZipResult
{
///<summary>
/// 压缩包中包含的所有文件,包括子目录下的文件
///</summary>
public GZipFileInfo[] Files =null;
///<summary>
/// 要压缩的文件数
///</summary>
publicint FileCount =0;
publiclong TempFileSize =0;
publiclong ZipFileSize =0;
///<summary>
/// 压缩百分比
///</summary>
publicint CompressionPercent =0;
///<summary>
/// 临时文件
///</summary>
publicstring TempFile =null;
///<summary>
/// 压缩文件
///</summary>
publicstring ZipFile =null;
///<summary>
/// 是否删除临时文件
///</summary>
publicbool TempFileDeleted =false;
publicbool Errors =false;
}
3.压缩操作类GZip,包括压缩解压等操作
/// <summary>
/// 压缩文件类
/// </summary>
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="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
(!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;
}
}
|
压缩解压缩的操作如下:
//Compress三个参数分别是“要压缩的目标目录”,“保存压缩文件的目录”,压缩文件名
GZip.Compress(@"E:\much\", @"E:\much\", "ziptest");
//Decompress三个参数分别是"压缩包所在目录","要解压到的目录",“压缩包名”
//如果压缩包所在目录不存在则解压不会成功
GZip.Decompress(@"E:\much\zip\", @"E:\much\zip\", "ziptest");