可適用於大文件壓縮
壓縮大文件時緩存buffer創建的時候出現溢出。那么這個緩存創建了多大呢?fs.Length!!沒錯,文件多大咱就創建多大,這樣相當於把整個文件放入內存
解決思路是開辟一個固定大小的緩存區,循環讀取文件進行壓縮,但是這里有個問題,壓縮時是先寫入ZipEntry再寫入文件數據的,而ZipEntry里面包含了crc信息,不把文件讀完,就計算不出來crc。這里采用讀取兩遍文件的策略,第一遍計算crc,第二遍再寫入文件數據。
修改之后,foreach循環里的代碼如下,直接上代碼
/// <summary> /// 壓縮大文件 /// </summary> /// <param name="args"></param> /// <param name="password"></param> public static void ZipFileMainBest(string[] args, string password) { List<string> files = new List<string>(); string[] filetypes; if (ConfigurationManager.AppSettings["FileType"].ToString() != "") { filetypes = ConfigurationManager.AppSettings["FileType"].ToString().Split(';'); Director(args[0], filetypes, files); } else { Director(args[0], files); } int count = files.Count; string[] ff = new string[count]; int i = 0; foreach (var item in files) { ff[i] = item.ToString(); i++; } string[] filenames = ff; //Directory.GetFiles(args[0]); if (filenames.Length > 0) { ZipOutputStream s = new ZipOutputStream(File.Create(args[1])); s.SetLevel(6); // 0 - store only to 9 - means best compression s.Password = md5.encrypt(password); s.Password = password; //md5.encrypt(password); Crc32 crc = new Crc32(); foreach (string file in filenames) { int readlen = 4096000; FileStream fs = File.OpenRead(file); byte[] buffer = new byte[4096000]; // 每次4M Array arr = file.Split('\\'); string le = arr.GetValue(arr.Length - 1).ToString(); ZipEntry entry = new ZipEntry(le); entry.DateTime = DateTime.Now; entry.Size = fs.Length; long remaindSize = fs.Length; // 計算crc crc.Reset(); while (remaindSize > 0) { if (remaindSize < readlen) readlen = (int)remaindSize; fs.Read(buffer, 0, readlen); remaindSize -= readlen; crc.Update(buffer, 0, readlen); } entry.Crc = crc.Value; s.PutNextEntry(entry); // 壓縮數據 readlen = 4096000; remaindSize = fs.Length; fs.Seek(0, SeekOrigin.Begin); while (remaindSize > 0) { if (remaindSize < readlen) readlen = (int)remaindSize; fs.Read(buffer, 0, readlen); remaindSize -= readlen; s.Write(buffer, 0, readlen); } s.Flush(); fs.Close(); } s.Finish(); s.Close(); } }
核心代碼
if (filenames.Length > 0) { ZipOutputStream s = new ZipOutputStream(File.Create(args[1])); s.SetLevel(6); // 0 - store only to 9 - means best compression s.Password = md5.encrypt(password); s.Password = password; //md5.encrypt(password); Crc32 crc = new Crc32(); foreach (string file in filenames) { int readlen = 4096000; FileStream fs = File.OpenRead(file); byte[] buffer = new byte[4096000]; // 每次4M Array arr = file.Split('\\'); string le = arr.GetValue(arr.Length - 1).ToString(); ZipEntry entry = new ZipEntry(le); entry.DateTime = DateTime.Now; entry.Size = fs.Length; long remaindSize = fs.Length; // 計算crc ,不計算也可行 crc.Reset(); while (remaindSize > 0) { if (remaindSize < readlen) readlen = (int)remaindSize; fs.Read(buffer, 0, readlen); remaindSize -= readlen; crc.Update(buffer, 0, readlen); } entry.Crc = crc.Value; s.PutNextEntry(entry); // 壓縮數據 readlen = 4096000; remaindSize = fs.Length; fs.Seek(0, SeekOrigin.Begin); while (remaindSize > 0) { if (remaindSize < readlen) readlen = (int)remaindSize; fs.Read(buffer, 0, readlen);//fs 是循序讀取文件流 remaindSize -= readlen; s.Write(buffer, 0, readlen); } s.Flush(); fs.Close(); } s.Finish(); s.Close(); }