如何用DotNetZip将50MB Zip文件分割为多个10MB Zip文件?
大Zip文件分割为指定大小的多份Zip解决方案
问题场景
开发照片售卖MVC应用时,需要将一个50MB、包含多张照片的Zip文件分割为多个10MB的Zip文件。尝试步骤为:解压原Zip到文件夹,设置每个Zip最大容量10MB,通过do while循环添加文件夹内文件直到Zip大小不超10MB,但最终仅生成了和原文件相同大小的50MB文件,未达到分割效果。
尝试的问题代码
[HttpPost] public IActionResult GenerateCompressFiles() { string dateCapture = DateTime.Now.ToString("ddMMyyyy"); string timeCapture = DateTime.Now.ToString("hhmmss"); string directory = Path.Combine(_env.ContentRootPath, "Uploads"); string outputDirectory = Path.Combine(_env.ContentRootPath, "Uploads/ZipTest"); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); string curFile = $"{directory}/MatiposExperencias-5345435435454.zip"; string zipFile = $"{directory}/MatiposExperencias-{dateCapture}{timeCapture}.zip"; var fileInfo = new FileInfo(zipFile); using (ZipFile zip = ZipFile.Read(curFile)) { zip.ExtractAll(outputDirectory, ExtractExistingFileAction.OverwriteSilently); } do { //Create A New Zip Archive using (ZipFile zipDest = new ZipFile()) { zipDest.AddFiles((System.IO.Directory.EnumerateFiles(outputDirectory)), false, ""); //This will add the files to the root zipDest.Save(zipFile); } _currentArchiveSize += fileInfo.Length; } while (_currentArchiveSize >= _maxArchiveSize || _currentArchiveSize + fileInfo.Length >= _maxArchiveSize); return RedirectToAction("Index","Home"); }
代码问题分析
- 重复添加全部文件:每次循环都直接添加解压文件夹里的所有文件,没有跟踪已处理的文件,导致生成的Zip始终是完整的50MB内容。
- 文件大小计算错误:
fileInfo是初始化空Zip时的信息,保存后未重新获取实际大小,导致_currentArchiveSize完全无法反映真实的Zip容量。 - 循环逻辑失效:循环条件无法正确触发“新建下一个Zip”的操作,没有实现“填满一个Zip就切换到下一个”的核心逻辑。
修复后的代码
[HttpPost] public IActionResult GenerateCompressFiles() { string dateCapture = DateTime.Now.ToString("ddMMyyyy"); string timeCapture = DateTime.Now.ToString("hhmmss"); string directory = Path.Combine(_env.ContentRootPath, "Uploads"); string outputDirectory = Path.Combine(_env.ContentRootPath, "Uploads/ZipTest"); const long maxArchiveSize = 10 * 1024 * 1024; // 10MB,转换为字节单位 // 确保目标目录存在 Directory.CreateDirectory(directory); Directory.CreateDirectory(outputDirectory); // 解压原Zip文件到临时文件夹 string curFile = $"{directory}/MatiposExperencias-5345435435454.zip"; using (ZipFile zip = ZipFile.Read(curFile)) { zip.ExtractAll(outputDirectory, ExtractExistingFileAction.OverwriteSilently); } // 获取所有待压缩的文件列表 var filesToZip = new List<string>(System.IO.Directory.EnumerateFiles(outputDirectory)); int currentFileIndex = 0; int zipSequence = 1; // 循环生成分割后的Zip文件 while (currentFileIndex < filesToZip.Count) { using (ZipFile zipDest = new ZipFile()) { long currentZipSize = 0; // 向当前Zip添加文件,直到接近最大容量 while (currentFileIndex < filesToZip.Count) { var targetFile = filesToZip[currentFileIndex]; var fileInfo = new FileInfo(targetFile); // 用原文件大小做保守判断(压缩后体积会更小,避免超出限制) if (currentZipSize + fileInfo.Length > maxArchiveSize) { break; // 当前Zip容量不足,停止添加 } zipDest.AddFile(targetFile, ""); currentZipSize += fileInfo.Length; currentFileIndex++; } // 保存当前分割Zip,用序号区分避免覆盖 string zipFileName = $"{directory}/MatiposExperencias-{dateCapture}{timeCapture}-{zipSequence}.zip"; zipDest.Save(zipFileName); zipSequence++; } } // 可选:清理解压后的临时文件 Directory.Delete(outputDirectory, true); return RedirectToAction("Index", "Home"); }
关键说明
- 跟踪已处理文件:用
currentFileIndex记录已添加到Zip的文件位置,避免重复打包。 - 容量判断逻辑:基于原文件大小做保守预估,确保生成的Zip不会超过10MB限制(压缩后实际体积会更小)。
- 分割文件命名:给每个分割Zip加上序号后缀,防止文件被覆盖。
- 临时文件清理:处理完成后可删除解压的临时文件夹,节省磁盘空间。
内容的提问来源于stack exchange,提问作者pipex98
相关产品推荐
相关产品推荐

