C#遍历Zip文件后HttpPostedFileBase内容长度归零的解决办法咨询
解决Zip文件校验后流为空的问题
你碰到的核心问题是**HttpPostedFileBase的输入流只能读取一次**——当你用ZipArchive读完流之后,流的位置已经到了末尾,而且默认它不支持Seek(重置位置),所以后续上传到Azure时自然就没有内容了。你之前复制数组的操作只是复制了对象引用,并没有复制流的实际内容,所以完全起不到作用。
首先得明确:要校验Zip包里的文件后缀,你肯定得读取Zip的内容(至少是目录结构),所以“不操作Zip文件”其实做不到,但我们可以通过缓存流内容的方式,既完成校验,又保留完整的文件流用于后续上传。
这里给你一个可行的解决方案:
步骤1:缓存文件流到MemoryStream
把每个上传文件的流复制到MemoryStream里,这样我们可以多次读取这个流——既用来解析Zip做校验,又能用来上传到Azure。
// 新增out参数返回缓存后的流,供后续上传使用 private static bool CanUploadBatchOfFiles(HttpPostedFileBase[] files, out List<MemoryStream> cachedFileStreams) { cachedFileStreams = new List<MemoryStream>(); bool isAllValid = true; foreach (var file in files) { // 把原流复制到MemoryStream缓存起来 var memoryStream = new MemoryStream(); file.InputStream.CopyTo(memoryStream); cachedFileStreams.Add(memoryStream); // 处理Zip文件的情况 if (file.FileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { // 重置流位置到开头,避免读取时跳过内容 memoryStream.Position = 0; // 设置leaveOpen: true,用完ZipArchive后不会关闭MemoryStream using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read, leaveOpen: true)) { foreach (var entry in zipArchive.Entries) { // 跳过Zip里的目录项(避免误判空名称的目录) if (string.IsNullOrEmpty(entry.Name)) continue; // 检查每个文件是否为.bin后缀 if (!entry.Name.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) { isAllValid = false; break; } } } // 校验完后再次重置流位置,方便后续上传使用 memoryStream.Position = 0; } // 处理单个.bin文件的情况 else if (!file.FileName.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) { isAllValid = false; break; } } return isAllValid; }
步骤2:使用缓存的流上传到Azure
校验通过后,不要用原HttpPostedFileBase的InputStream,而是用我们缓存的MemoryStream来上传:
// 调用校验方法,获取缓存的流 if (CanUploadBatchOfFiles(files, out var cachedStreams)) { // 遍历每个缓存的流,上传到Azure Blob Storage for (int i = 0; i < files.Length; i++) { var originalFile = files[i]; var uploadStream = cachedStreams[i]; // 替换成你实际的Azure上传代码,例如: // var blobClient = containerClient.GetBlobClient(originalFile.FileName); // await blobClient.UploadAsync(uploadStream, overwrite: true); } } // 用完后释放MemoryStream,避免内存泄漏 foreach (var stream in cachedStreams) { stream.Dispose(); }
为什么之前的复制数组没用?
HttpPostedFileBase是引用类型,你复制数组只是把每个对象的引用复制了一份,所有引用指向的还是同一个HttpPostedFileBase实例,它的InputStream还是那个只能读一次的流——所以无论怎么复制数组,只要读取过流,后续就会为空。
内容的提问来源于stack exchange,提问作者Martin Nilsson
相关产品推荐
相关产品推荐

