python-docx:打开文件时出错 - "Bad magic number for file header" / "EOFError"

python-docx: Error opening file - "Bad magic number for file header" / "EOFError"

我工作的公司分发使用 python-docx 库的文档汇编软件。该软件在打开文档的每个生成的文档上运行一个函数,并对未正确转义的字符(即“&”->“&”)进行简单的搜索和替换。

FYI 实际文档汇编使用 python-docx-template。但是,错误发生在文档已经组装之后,并且错误是由搜索和替换功能触发的,该功能仅使用 python-docx.

最近,我们遇到了一些无法在客户端部署中生成文档的案例。他们在实例化文档对象的这一行抛出错误:

doc = Document(docx=Path(doc_path))

我们发现了两个错误:

raise BadZipFile("Bad magic number for file header")

raise EOFError

该软件被广泛使用,我们以前从未遇到过这个问题。我们无法在我们的测试环境中重现它。该错误仅在过去一周才开始出现,但在更新后已出现在多个客户端上。该软件将多次无法生成特定文档,但会在几次尝试后成功。

我们只看到它发生在一个文档中,但所有文档都使用相同的搜索和替换功能,就像我说的那样,错误只是间歇性出现在有问题的文档中。

此搜索和替换功能的代码没有变化,我想不出我们的文档汇编过程有任何其他有意义的差异可以解释这一点。

我很难找到有关 python-docx 库可能导致此问题的具体原因的信息。这是生成的文档已损坏的标志吗?如果有人能够阐明可能的原因,那将非常有帮助!

这是两个错误的堆栈跟踪:

错误的幻数...

File "/home/user/app/application/document_assembly/core_da.py", line 524, in translate_ampersands
    doc = Document(docx=Path(doc_path))
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/api.py", line 25, in Document
    document_part = Package.open(docx).main_document_part
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/package.py", line 116, in open
    pkg_reader = PackageReader.from_file(pkg_file)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 36, in from_file
    phys_reader, pkg_srels, content_types
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 69, in _load_serialized_parts
    for partname, blob, reltype, srels in part_walker:
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 104, in _walk_phys_parts
    part_srels = PackageReader._srels_for(phys_reader, partname)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 83, in _srels_for
    rels_xml = phys_reader.rels_xml_for(source_uri)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/phys_pkg.py", line 129, in rels_xml_for
    rels_xml = self.blob_for(source_uri.rels_uri)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/phys_pkg.py", line 108, in blob_for
    return self._zipf.read(pack_uri.membername)
  File "/usr/lib/python3.6/zipfile.py", line 1337, in read
    with self.open(name, "r", pwd) as fp:
  File "/usr/lib/python3.6/zipfile.py", line 1396, in open
    raise BadZipFile("Bad magic number for file header")

zipfile.BadZipFile: Bad magic number for file header

EOFError

File "/home/user/app/application/document_assembly/core_da.py", line 524, in translate_ampersands
    doc = Document(docx=Path(doc_path))
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/api.py", line 25, in Document
    document_part = Package.open(docx).main_document_part
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/package.py", line 116, in open
    pkg_reader = PackageReader.from_file(pkg_file)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 36, in from_file
    phys_reader, pkg_srels, content_types
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 69, in _load_serialized_parts
    for partname, blob, reltype, srels in part_walker:
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 110, in _walk_phys_parts
    for partname, blob, reltype, srels in next_walker:
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/pkgreader.py", line 105, in _walk_phys_parts
    blob = phys_reader.blob_for(partname)
  File "/home/user/app-venv/lib/python3.6/site-packages/docx/opc/phys_pkg.py", line 108, in blob_for
    return self._zipf.read(pack_uri.membername)
  File "/usr/lib/python3.6/zipfile.py", line 1338, in read
    return fp.read()
  File "/usr/lib/python3.6/zipfile.py", line 858, in read
    buf += self._read1(self.MAX_N)
  File "/usr/lib/python3.6/zipfile.py", line 940, in _read1
    data += self._read2(n - len(data))
  File "/usr/lib/python3.6/zipfile.py", line 975, in _read2
    raise EOFError
EOFError

这两个错误都表明指定的文件不是有效的 zip 存档。所以我预计文件的写入出了问题(在查找和替换之前的步骤)。

我会先在写入文件后停止进程,然后查看文件是否存在于文件系统中以及是否可以使用 Word 手动打开它。这应该将问题一分为二并将其缩小为写作问题或阅读问题。

写入时可能会出现错误,但未被捕获或发生其他错误,从而留下一个空文件或未刷新(打开)的文件。因此,有一种方法可以监控该步骤可能是个好主意。将写入日志作为管理方式浮现在脑海中。

检查出现故障的特定情况并设法重现故障将至关重要。如果那不可能,那将是一条充满猜测和双方失望的艰难道路。

事实证明,在这种情况开始发生之前最近添加了一些代码,这有效地向服务器发送了一个重复请求以生成有问题的文档。这些请求似乎 运行 并行 - 这令人惊讶,因为我预计冲突会更频繁地发生(使用相同的模板文件,生成的文档写入相同的目录)。

似乎如果请求的顺序发生在特定的时间,一个请求的“查找和替换”操作将 运行 变成另一个请求的“保存”操作。所以换句话说,我认为一个请求试图打开一个正在保存的文档。

所以我很高兴 python-docx 库没有更晦涩的东西,这本来就更难确定。