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

如何将pdfrw的PdfReader对象转换为字节数组或文件流?内存中PDF表单编辑技术问询

在内存中处理pdfrw编辑后的PDF(无需写入本地文件)

我正在为一款PDF编辑器应用开发一个简单的概念验证示例,用Python脚本展示如何用pdfrw库编辑带表单的PDF。现在遇到一个问题:我不想把编辑后的PDF写入本地文件,因为文件的打开/关闭会由外部代码处理,希望所有操作都在内存中完成,返回字节流或io.BytesIO对象,而不是本地文件。

我的代码大致如下:

import pdfrw
from io import BytesIO

class FormFiller:
    def __fill_pdf__(self, input_pdf_filestream : bytes, data_dict : dict):
        template_pdf : pdfrw.PdfReader = pdfrw.PdfReader(input_pdf_filestream)
        # 这里是表单填充的逻辑
        for page in template_pdf.pages:
            annotations = page['/Annots']
            if annotations:
                for annot in annotations:
                    if annot['/Subtype'] == '/Widget' and '/T' in annot:
                        field_name = annot['/T'][1:-1]  # 去掉前后的括号
                        if field_name in data_dict:
                            annot.update(pdfrw.PdfDict(V=f"{data_dict[field_name]}"))
                            annot.update(pdfrw.PdfDict(Ff=1))  # 设置为只读(可选)
        return template_pdf

    def fillForm(self,mapper):
        value_mapping : dict = mapper.getValues()
        filled_pdf : pdfrw.PdfReader = self.__fill_pdf__(self.filestream, value_mapping)
        # 关键节点:如何把filled_pdf转为内存中的字节流?
        # pdfrw的PdfWriter似乎只能写入本地文件?

    def __init__(self, filestream : bytes):
        self.filestream : bytes = filestream

解决方案:用BytesIO让pdfrw在内存中输出

别担心,pdfrw的PdfWriter其实完全支持写入内存流,只是可能文档没强调这点!你只需要用io.BytesIO作为输出目标,而不是传本地文件名。

修改你的fillForm方法,改成这样:

from io import BytesIO

def fillForm(self, mapper):
    value_mapping = mapper.getValues()
    filled_pdf = self.__fill_pdf__(self.filestream, value_mapping)
    
    # 创建一个空的内存字节流
    output_stream = BytesIO()
    
    # 用PdfWriter把编辑好的PDF写入这个内存流
    writer = pdfrw.PdfWriter()
    writer.write(output_stream, filled_pdf)
    
    # 一定要把流的指针移到开头!不然外部代码读的时候会从末尾开始,拿不到内容
    output_stream.seek(0)
    
    # 这里可以返回BytesIO对象,或者如果需要字节数组的话用output_stream.getvalue()
    return output_stream

关键细节说明:

  • PdfWriter.write()的第一个参数不是只能传字符串文件名,它接受任何实现了文件接口的对象——BytesIO正好符合要求,它在内存中模拟了文件的行为。
  • 写完之后必须调用seek(0),因为写入操作会把指针移到流的末尾,后续读取操作需要从开头开始才能拿到完整内容。
  • 如果外部代码需要的是原始字节数组而不是BytesIO对象,直接返回output_stream.getvalue()就可以了,这个方法会返回流中的所有字节。

备选方案:如果pdfrw不够用,可以换这些库

如果后续你发现pdfrw对某些复杂PDF表单的支持不太好,或者需要更多高级功能,这些库也能很好支持内存中处理PDF:

  • PyPDF2/PyPDF4:表单填充的API更直观,同样支持用BytesIO做内存输出,社区活跃度也更高。
  • pdfplumber:虽然主打PDF提取,但配合其他库也能做表单编辑,对复杂PDF的兼容性不错。

不过就你当前的需求来说,用BytesIO配合pdfrw完全能解决问题,没必要更换库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:27:51