.NET 8中ZipFileEntry流读取不完整,无法正确复制ZIP文件内容到字节数组
.NET 8中ZipFileEntry流读取不完整,无法正确复制ZIP文件内容到字节数组
你遇到的这个问题其实是流读取的常见坑——Stream.Read()方法并不会保证一次性读取你指定的所有字节,它只会返回实际成功读取的字节数。这在处理ZipArchiveEntry打开的压缩流时特别明显,因为这类流是分块解压并返回数据的,不会一下子把所有内容都加载到内存里。
你看你的代码里只调用了一次Read(rawData, 0, rawData.Length),如果文件实际内容是100KB,但这次调用可能只读到了一部分,剩下的还留在流里没被读取,所以输出的readBytes会比预期的100KB小。
下面给你几个实用的解决办法:
方案一:循环读取直到流结束
通过循环不断调用Read方法,直到返回值为0(表示流已经读完),把每次读取到的字节拼接起来:
using System; using System.IO.Compression; using System.IO; namespace ConsoleApp2 { internal class Program { static void Main(string[] args) { using var zipfile = ZipFile.OpenRead("Test.zip"); var zipfileEntry = zipfile.GetEntry("Data20240810"); if (zipfileEntry == null) { Console.WriteLine("找不到指定的ZIP条目"); return; } using var fileStream = zipfileEntry.Open(); using var ms = new MemoryStream(); int readBytes; var buffer = new byte[4096]; // 用4KB的缓冲块读取更高效 while ((readBytes = fileStream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, readBytes); } var rawData = ms.ToArray(); Console.WriteLine($"读取到的总字节数:{rawData.Length}"); Console.WriteLine($"ZIP条目的实际大小:{zipfileEntry.Length}"); } } }
方案二:用CopyTo方法简化代码
Stream.CopyTo()方法内部已经帮你实现了循环读取的逻辑,直接把Zip流的内容复制到MemoryStream,再转成字节数组就行,代码更简洁:
using System; using System.IO.Compression; using System.IO; namespace ConsoleApp2 { internal class Program { static void Main(string[] args) { using var zipfile = ZipFile.OpenRead("Test.zip"); var zipfileEntry = zipfile.GetEntry("Data20240810"); if (zipfileEntry == null) { Console.WriteLine("找不到指定的ZIP条目"); return; } using var fileStream = zipfileEntry.Open(); using var ms = new MemoryStream(); fileStream.CopyTo(ms); var rawData = ms.ToArray(); Console.WriteLine($"读取到的总字节数:{rawData.Length}"); Console.WriteLine($"ZIP条目的实际大小:{zipfileEntry.Length}"); } } }
最后再提醒几个细节:
- 一定要用
using语句包裹ZipArchive、Stream这些实现了IDisposable的对象,避免资源泄漏。 - 可以通过
zipfileEntry.Length获取条目的实际大小,用来验证读取结果是否正确。 - 不要固定创建100KB的字节数组,如果条目大小不是刚好100KB,要么浪费空间要么不够用,用MemoryStream动态扩容更灵活。
备注:内容来源于stack exchange,提问作者dovepoppo
相关产品推荐
相关产品推荐

