如何计算Azure共享文件中添加JSON后的新Zip归档文件大小?
解决Azure中Zip归档大小计算与调整问题
问题背景
流程为:输入Zip归档 → 解压至Azure共享文件夹 → 添加JSON文件 → 重新打包为包含原数据+JSON的新Zip。核心痛点是无法准确计算新归档的最终大小,也无法调整文件大小去除无效空白空间。
当前困境
- 用
原归档大小×1.5 + JSON长度估算maxSize,但因原归档压缩率未知,估算误差极大; - 直接求和解压目录所有文件大小不可行:小文件(如单字符TXT)打包后的Zip大小会超过文件总和,且解压时会触发「归档大小与负载块不匹配」错误;
- 尝试过创建0大小结果文件,压缩时计算大小再通过
SetHttpHeaders调整,但未成功。
解决方案
核心思路:通过内存流中转压缩,先获取准确大小再上传
避免直接在Azure文件流上创建ZipArchive(需要预指定大小),先在本地MemoryStream中完成压缩,拿到精确的最终大小后,再创建对应大小的Azure文件并写入数据,彻底解决预估算的问题。
修改后的代码实现
private async Task<ShareFileClient> CreateNewArchive(ShareDirectoryClient rootDirectory, string fileName, ShareDirectoryClient extractDirectory) { // 先在内存流中完成Zip压缩,获取准确大小 using var memoryStream = new MemoryStream(); using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: true)) { foreach (var item in extractDirectory.GetFilesAndDirectories()) await CreateFromAny(zipArchive, item, extractDirectory, string.Empty); } // 获取压缩后的准确大小 long finalSize = memoryStream.Length; var resultFile = rootDirectory.GetFileClient(fileName); // 创建对应大小的Azure文件并写入数据 var options = new ShareFileOpenWriteOptions { MaxSize = finalSize }; await using var azureStream = await resultFile.OpenWriteAsync(true, 0, options); memoryStream.Position = 0; await memoryStream.CopyToAsync(azureStream); await azureStream.FlushAsync(); return resultFile; } private async Task CreateFromAny(ZipArchive archive, ShareFileItem entry, ShareDirectoryClient sourceDir, string currentPath) { if (entry.IsDirectory) { await CreateFromDirectory(archive, sourceDir.GetSubdirectoryClient(entry.Name), currentPath); } else { var path = Path.Combine(currentPath, entry.Name); var extractedFile = sourceDir.GetFileClient(entry.Name); await using (var fileZip = archive.CreateEntry(path).Open()) { await using (var entryStream = await extractedFile.OpenReadAsync()) { await entryStream.CopyToAsync(fileZip); await entryStream.FlushAsync(); } await fileZip.FlushAsync(); } } } private async Task CreateFromDirectory(ZipArchive archive, ShareDirectoryClient sourceDir, string currentPath) { currentPath = Path.Combine(currentPath, sourceDir.Name); archive.CreateEntry($"{currentPath}/"); foreach (var file in sourceDir.GetFilesAndDirectories()) await CreateFromAny(archive, file, sourceDir, currentPath); }
方案优势
- 完全准确的大小计算:通过MemoryStream中转,直接获取压缩后的真实长度,无需估算;
- 避免Azure文件的空白空间:创建文件时直接指定最终大小,不会产生无效空白块;
- 解决解压报错问题:因为最终文件大小与实际压缩数据完全匹配,不会出现「归档大小与负载块不匹配」的错误。
内容的提问来源于stack exchange,提问作者embolshov
相关产品推荐
相关产品推荐

