从Blob Storage提取tar.gz并上传至另一Blob Storage时文件为0字节的问题
问题:提取Tar.gz文件后上传至Azure Blob Storage得到0字节文件
问题背景
从Azure Blob Storage读取tar.gz文件,本地解压到文件夹正常,但尝试将解压结果上传至另一个Blob Storage时,得到0字节的Blob文件,无报错信息。
本地可用代码:
var blobEndPointSrc = "https://storageaccountname.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientSrc = GetBlobServiceClientSAS(blobEndPointSrc); var blobClientSrc = blobContainerClientSrc.GetBlobClient("file.tar.gz"); var blobDownloadInfo = blobClientSrc.OpenRead(); using Stream gzipStream = new GZipInputStream(blobDownloadInfo); // 本地解压正常 using var tarArchive = TarArchive.CreateInputTarArchive(gzipStream); tarArchive.ExtractContents(@"D:\file");
尝试上传的错误代码:
// using var tarArchive = TarArchive.CreateInputTarArchive(gzipStream); // tarArchive.ExtractContents(@"D:\file"); var tarBuffer = TarBuffer.CreateInputTarBuffer(gzipStream); Stream result = new MemoryStream(); TarBuffer.CreateOutputTarBuffer(result); var blobEndPointDst = = "https://storageaccountname2.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientDst = GetBlobServiceClientSAS(blobEndPointDst); var blobClientDst = blobContainerClient1.GetBlobClient("extracted_file"); blobClientDst.Upload(result, true);
错误原因
- 未执行实际内容读写:仅初始化了
TarBuffer,但未读取源tar文件的条目内容并写入输出流,导致MemoryStream为空。 - 流位置未重置:即使写入内容,上传前未将
MemoryStream的Position设为0,上传时从流末尾读取,最终上传0字节。 - 代码笔误:
blobEndPointDst = =多了一个等号;blobClientDst使用了错误的容器客户端blobContainerClient1(应为blobContainerClientDst)。
修正方案
方案1:逐个上传解压后的文件(对应本地解压到文件夹场景)
遍历tar.gz中的每个文件条目,直接将条目内容上传至目标Blob Storage,无需本地存储:
var blobEndPointSrc = "https://storageaccountname.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientSrc = GetBlobServiceClientSAS(blobEndPointSrc); var blobClientSrc = blobContainerClientSrc.GetBlobClient("file.tar.gz"); using var blobDownloadStream = blobClientSrc.OpenRead(); using var gzipStream = new GZipInputStream(blobDownloadStream); using var tarArchive = TarArchive.CreateInputTarArchive(gzipStream); // 初始化目标Blob容器客户端 var blobEndPointDst = "https://storageaccountname2.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientDst = GetBlobServiceClientSAS(blobEndPointDst); // 绑定进度事件,处理每个文件条目上传 tarArchive.ProgressMessageEvent += (sender, args) => { var entry = args.TarEntry; if (!entry.IsDirectory) { // 以tar条目名称作为Blob名称创建客户端 var blobClientDst = blobContainerClientDst.GetBlobClient(entry.Name); // 打开条目内容流并上传 using var entryStream = entry.OpenEntryStream(); blobClientDst.Upload(entryStream, overwrite: true); } }; // 触发提取流程,自动调用事件处理上传 tarArchive.ExtractContents();
方案2:将解压内容重新打包为Tar后上传
如果需要将所有解压文件重新打包成单个Tar文件上传,可直接通过流复制,避免本地内存占用:
var blobEndPointSrc = "https://storageaccountname.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientSrc = GetBlobServiceClientSAS(blobEndPointSrc); var blobClientSrc = blobContainerClientSrc.GetBlobClient("file.tar.gz"); using var blobDownloadStream = blobClientSrc.OpenRead(); using var gzipStream = new GZipInputStream(blobDownloadStream); using var inputTarArchive = TarArchive.CreateInputTarArchive(gzipStream); // 初始化目标Blob客户端 var blobEndPointDst = "https://storageaccountname2.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientDst = GetBlobServiceClientSAS(blobEndPointDst); var blobClientDst = blobContainerClientDst.GetBlobClient("extracted_file.tar"); // 直接打开Blob的写入流,边读边写 using var uploadStream = blobClientDst.OpenWrite(overwrite: true); using var outputTarArchive = TarArchive.CreateOutputTarArchive(uploadStream); // 遍历输入Tar的条目,复制到输出Tar inputTarArchive.ProgressMessageEvent += (sender, args) => { var entry = args.TarEntry; if (!entry.IsDirectory) { outputTarArchive.WriteEntry(entry, recurse: true); } }; inputTarArchive.ExtractContents(); outputTarArchive.Close(); // 确保所有内容写入上传流
推荐替代库
.NET原生System.IO.Compression
无需第三方依赖,.NET 6及以上版本支持TarReader/TarWriter,API更简洁稳定:
var blobEndPointSrc = "https://storageaccountname.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientSrc = GetBlobServiceClientSAS(blobEndPointSrc); var blobClientSrc = blobContainerClientSrc.GetBlobClient("file.tar.gz"); using var blobDownloadStream = blobClientSrc.OpenRead(); using var gzipStream = new GZipStream(blobDownloadStream, CompressionMode.Decompress); using var tarReader = new TarReader(gzipStream); var blobEndPointDst = "https://storageaccountname2.blob.core.windows.net/data-source-raw?etc..."; var blobContainerClientDst = GetBlobServiceClientSAS(blobEndPointDst); TarEntry entry; while ((entry = tarReader.GetNextEntry()) != null) { if (!entry.IsDirectory) { var blobClientDst = blobContainerClientDst.GetBlobClient(entry.Name); using var entryStream = entry.OpenEntryStream(); blobClientDst.Upload(entryStream, overwrite: true); } }
内容的提问来源于stack exchange,提问作者user9566597
相关产品推荐
相关产品推荐

