SharpZipLib.dll 压缩文件,可以应用于MVC, webform. C# windows application 等等地方
Nuget 安装:Install-Package ICSharpCode.SharpZipLib.dll
private void WriteZipFile(string[] filesToZip, string writeToFilePath) { try { Crc32 crc = new Crc32(); ZipOutputStream s = new ZipOutputStream(System.IO.File.Create(writeToFilePath)); s.SetLevel(9); // 0 - store only to 9 - means best compression for (int i = 0; i < filesToZip.Length; i++) { // Must use a relative path here so that files show up in the Windows Zip File Viewer // .. hence the use of Path.GetFileName(...) ZipEntry entry = new ZipEntry(Path.GetFileName(filesToZip[i])); entry.DateTime = DateTime.Now; // Read in the using (FileStream fs = System.IO.File.OpenRead(filesToZip[i])) { byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); // set Size and the crc, because the information // about the size and crc should be stored in the header // if it is not set it is automatically written in the footer. // (in this case size == crc == -1 in the header) // Some ZIP programs have problems with zip files that don't store // the size and crc in the header. entry.Size = fs.Length; fs.Close(); crc.Reset(); crc.Update(buffer); entry.Crc = crc.Value; s.PutNextEntry(entry); s.Write(buffer, 0, buffer.Length); } } s.Finish(); s.Close(); } catch (Exception ex) { HttpContext.Trace.Warn(ex.ToString()); } }
今天经过大文件压缩测试,发现这里有一个内存溢出的bug,当文件大于500M左右时,
byte[] buffer = new byte[fs.Length]; //会发生内存溢出
经查资料,解决方法是,边读文件流边压缩,这样就可以避免Web服务器一次性都到的内存里,如果先把文件压缩到MemoryStream,最后在输出就会消耗大量的内存在MemoryStream里。也就容易引起内存溢出了
private void WriteZipFile(string[] filesToZip, string writeToFilePath) { try { Stream fs1 = System.IO.File.OpenWrite(writeToFilePath); ZipOutputStream s = new ZipOutputStream(fs1); s.SetLevel(9); // 0 - store only to 9 - means best compression for (int i = 0; i < filesToZip.Length; i++) { ZipEntry entry = new ZipEntry(Path.GetFileName(filesToZip[i])); entry.DateTime = DateTime.Now; using (var fs = new FileStream(filesToZip[i], FileMode.Open, FileAccess.Read)) { entry.Size = fs.Length; //这个时候是没用把文件读到内存里的 s.PutNextEntry(entry); byte[] buffer = new byte[10240]; //边读边写 int bytesRead = 0; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { s.Write(buffer, 0, bytesRead); } s.CloseEntry(); } } s.Finish(); s.Close(); fs1.Close(); } catch (Exception ex) { HttpContext.Trace.Warn(ex.ToString()); } }
MVC 输出:File(Server.MapPath("文件路径"), "application/zip", "文件名");
WebForm 输出同样要避免500M文件容易出现的内存溢出:
public void DownloadFile(string physicalFilePath) { FileStream stream = null; try { stream = new FileStream(physicalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] buffer = new byte[10240]; int bytesRead = 0; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { HttpContext.Response.OutputStream.Write(buffer, 0, bytesRead); } HttpContext.Response.ContentType = "application/octet-stream "; HttpContext.Response.AppendHeader("Content-Disposition ", "attachment;filename= " + System.IO.Path.GetFileName(physicalFilePath)); HttpContext.Response.End(); } finally { stream.Close(); } }