You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重置流位置时ZipArchive抛出ArgumentException异常的原因

多个Stream压缩为ZipArchive时在Xamarin iOS物理设备上的异常问题

我需要将多个Stream实例压缩为Zip包,使用的代码如下:

using var memoryStream = new MemoryStream();            
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
    foreach (var stream in streams)
    {
        var entry = zipArchive.CreateEntry($"{Guid.NewGuid()}.jpeg");

        using var entryStream = entry.Open();
        stream.CopyTo(entryStream);           
    }
}

memoryStream.Seek(0, SeekOrigin.Begin);
// memoryStream.Position = 0; // 同样会抛出异常 

当streams中只有少量元素时代码运行正常,但包含10个元素时会失败,错误出现在最后一行重置流位置的代码。错误信息如下:

{System.ArgumentException: Offset and length were out of bounds for
the array or count is greater than the number of elements from index
to the end of the source collection. at System.IO.MemoryStream.Read
(System.Byte[] buffer, System.Int32 offset, System.Int…}

调试器中内存流的状态为:

CanRead: true
CanSeek: true
CanWrite: true
Capacity: 8534016
Length: 6853402
Position: 6853402

注:该代码运行在Xamarin iOS物理设备上,请问是什么原因导致此错误抛出?


问题原因及解决思路

核心原因

这个异常是Xamarin iOS基于的Mono运行时对ZipArchive和MemoryStream的实现细节导致的:

  • 尽管构造ZipArchive时指定了leaveOpen: true,但在ZipArchive的Dispose方法执行(即using块结束)时,Mono的实现可能仍在异步或延迟完成Zip包的收尾写入操作,比如写入目录结构、校验信息。
  • 此时立即调用Seek或修改Position,会干扰MemoryStream内部缓冲区的同步状态,导致后续操作时出现数组越界的参数异常。当处理的文件数量多、总数据量大时,这种延迟写入的冲突概率会显著提升。

解决方法

  1. 强制刷新流缓冲区
    在ZipArchive的using块结束后,先调用Flush()确保所有缓冲数据完成写入,再重置流位置:
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
    // 原有压缩逻辑
}

memoryStream.Flush(); // 新增刷新操作
memoryStream.Seek(0, SeekOrigin.Begin);
  1. 复制到新的MemoryStream
    将原流的内容复制到一个新的MemoryStream中,避免原流的状态冲突:
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
    // 原有压缩逻辑
}

var newStream = new MemoryStream();
memoryStream.CopyTo(newStream);
newStream.Seek(0, SeekOrigin.Begin);
// 使用newStream替代原memoryStream
  1. 检查输入流的位置
    确保每个输入的stream都是从起始位置开始复制,避免因输入流Position异常导致的写入数据错乱:
foreach (var stream in streams)
{
    stream.Seek(0, SeekOrigin.Begin); // 新增重置输入流位置
    var entry = zipArchive.CreateEntry($"{Guid.NewGuid()}.jpeg");
    using var entryStream = entry.Open();
    stream.CopyTo(entryStream);           
}

内容的提问来源于stack exchange,提问作者user246392

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:05:32