Blazor WebAssembly iText7处理PDF报Cannot Access Closed Stream
问题根因
触发"Cannot Access Closed Stream"异常的核心原因是iText7的默认设计:当PdfDocument完成写入、执行释放/关闭操作时,绑定的PdfWriter会默认调用传入输出流的Close()方法,直接把外部创建的MemoryStream释放,后续跨方法访问自然报错。哪怕手动去掉pdfOut的using声明,只要iText走完PDF完整写入流程触发文档关闭,一样会关闭底层流。
另外之前尝试把return语句放在using块内的方案本身就不可行:此时pdfOut还没完成PDF尾部字典、交叉引用表的写入,流里存储的PDF内容是损坏的,根本无法正常读取。
实现方案
完全不需要耦合所有处理逻辑到单个方法,也不需要反复在byte[]和MemoryStream之间转换产生额外开销,只要修改iText的流关闭配置、做好流指针重置,就能实现MemoryStream跨方法复用:
- 初始化
PdfWriter时调用SetCloseStream(false),禁止iText主动关闭外部传入的MemoryStream - 每个处理步骤完成、iText对象释放后,必须将MemoryStream的
Position属性设为0,保证下一个处理步骤能从流的起始位置读取完整PDF内容 - 所有PDF处理步骤全部完成后,再统一释放用到的MemoryStream资源即可
修正后的RemoveText方法实现如下:
public async Task<(MemoryStream, string)> RemoveText(MemoryStream pdfFile) { var outStream = new MemoryStream(); string result = ""; using (var pdfIn = new PdfDocument(new PdfReader(pdfFile))) { // 配置PdfWriter不关闭底层输出流 using (var pdfOut = new PdfDocument(new PdfWriter(outStream).SetCloseStream(false))) { // 执行文本移除相关逻辑 result = doneStuff; } } // 重置流指针到起始位置,供后续处理步骤读取 outStream.Position = 0; return (outStream, result); }
后续处理注意事项
拿到返回的outputPdf流后可以直接传入分页处理方法,如果分页方法内部也使用iText7操作PDF,记得给方法内的PdfWriter同样加上SetCloseStream(false)配置,处理完成后也重置流位置即可。
所有步骤处理完成后,如果需要获取最终的PDF文件字节,直接调用最终MemoryStream的ToArray()方法即可——该方法不依赖流的开放状态,哪怕后续释放流也能拿到完整的文件内容。
内容的提问来源于stack exchange,提问作者Kaotic
相关产品推荐
相关产品推荐

