Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python pypdf将多个pdf文件合并为一个pdf_Python_Pypdf - Fatal编程技术网

Python pypdf将多个pdf文件合并为一个pdf

Python pypdf将多个pdf文件合并为一个pdf,python,pypdf,Python,Pypdf,如果我有1000多个pdf文件需要合并成一个pdf input = PdfFileReader() output = PdfFileWriter() filename0000 ----- filename 1000 input = PdfFileReader(file(filename, "rb")) pageCount = input.getNumPages() for iPage in range(0, pageCount): output.addPa

如果我有1000多个pdf文件需要合并成一个pdf

input = PdfFileReader()
output = PdfFileWriter()
filename0000 ----- filename 1000
    input = PdfFileReader(file(filename, "rb"))
    pageCount = input.getNumPages()
    for iPage in range(0, pageCount):
        output.addPage(input.getPage(iPage))
outputStream = file("document-output.pdf", "wb")
output.write(outputStream)
outputStream.close()
input=PdfileReader(文件(filename500+,“rb”))
时,执行上述代码

错误消息:
IOError:[Errno 24]打开的文件太多:


我认为这是一个bug,如果不是,我该怎么办?

可能正是它所说的,您正在打开许多文件。
您可以显式使用
f=file(文件名)。。。f、 在循环中关闭()
,或使用
with
语句。以便正确关闭每个打开的文件

问题在于,在任何给定时间,您只能打开一定数量的文件。有很多方法可以改变这个(),但我认为您不需要这个

您可以尝试关闭for循环中的文件:

input = PdfFileReader()
output = PdfFileWriter()
for file in filenames:
   f = open(file, 'rb')
   input = PdfFileReader(f)
   # Some code
   f.close()

我最近遇到了完全相同的问题,所以我深入研究了PyPDF2,看看发生了什么,以及如何解决它

注意:我假设
filename
是格式良好的文件路径字符串。假设我的所有代码都是相同的

简短的回答

使用
PdfFileMerger()
类代替
PdfFileWriter()
类。我已尝试提供以下内容,以尽可能接近您的内容:

from PyPDF2 import PdfFileMerger, PdfFileReader

[...]

merger = PdfFileMerger()
for filename in filenames:
    merger.append(PdfFileReader(file(filename, 'rb')))

merger.write("document-output.pdf")
长答案

使用
PdfFileReader
PdfFileWriter
的方法是保持每个文件打开,并最终导致Python生成IOError 24。更具体地说,当您向
PdfFileWriter
添加页面时,您是在打开的
PdfFileReader
中添加对该页面的引用(因此,如果关闭该文件,会出现注意到的IO错误)。Python检测到仍要引用的文件,并且不执行任何垃圾收集/自动关闭文件,尽管重新使用了文件句柄。它们将保持打开状态,直到
PdfFileWriter
不再需要访问它们,即在代码中的
output.write(outputStream)

要解决此问题,请在内容的内存中创建副本,并允许关闭文件。在我的PyPDF2代码冒险中,我注意到
PdfFileMerger()
类已经有了这个功能,所以我没有重新发明轮子,而是选择使用它。不过,我了解到,我最初对
PdfFileMerger
的观察不够仔细,它只在特定条件下创建副本

我最初的尝试如下所示,并导致了相同的IO问题:

merger = PdfFileMerger()
for filename in filenames:
    merger.append(filename)

merger.write(output_file_path)
查看PyPDF2源代码,我们看到
append()
需要传递
fileobj
,然后使用
merge()
函数,将其最后一页作为新文件位置传递
merge()
使用
fileobj
执行以下操作(在使用
PdfFileReader(fileobj)打开它之前)

我们可以看到,
append()
选项确实接受字符串,并且在这样做时,假定它是一个文件路径,并在该位置创建一个文件对象。最终结果与我们试图避免的完全相同。一个
PdfFileReader()
对象将打开一个文件,直到文件最终被写入

但是,如果我们在路径字符串传递到
append()
之前创建文件路径字符串的file对象或路径字符串的
PdfFileReader
(请参见编辑2)对象,它将自动为我们创建一个副本作为
StringIO
对象,从而允许Python关闭文件

我建议使用更简单的
merge.append(file(filename,'rb'))
,因为其他人报告说,即使在调用
writer.close()
之后,
PdfFileReader
对象也可能在内存中保持打开状态

希望这有帮助

编辑:我假设您使用的是
PyPDF2
,而不是
PyPDF
。如果您不使用,我强烈建议您切换,因为PyPDF已不再维护,作者已正式批准分阶段开发PyPDF2

如果由于某种原因您无法切换到PyPDF2(许可、系统限制等),则
Pdfilemerger
将不可用。在这种情况下,您可以重新使用PyPDF2的
合并
功能中的代码(如上所述)将文件的副本创建为
StringIO
对象,并在代码中使用该副本代替文件对象


编辑2:先前建议使用的
merge.append(PdfileReader(file(filename,'rb'))
根据注释进行了更改(感谢@Agostino)。

pdfrw包一次读取所有文件,因此不会出现打开文件过多的问题。这是一个连接脚本示例

相关部分——假设
inputs
是一个输入文件名列表,
outfn
是一个输出文件名:

from pdfrw import PdfReader, PdfWriter

writer = PdfWriter()
for inpfn in inputs:
    writer.addpages(PdfReader(inpfn).pages)
writer.write(outfn)

免责声明:我是pdfrw的主要作者。

我编写此代码是为了帮助回答以下问题:-

import sys
import os
import PyPDF2

merger = PyPDF2.PdfFileMerger()

#get PDFs files and path

path = sys.argv[1]
pdfs = sys.argv[2:]
os.chdir(path)


#iterate among the documents
for pdf in pdfs:
    try:
        #if doc exist then merge
        if os.path.exists(pdf):
            input = PyPDF2.PdfFileReader(open(pdf,'rb'))
            merger.append((input))
        else:
            print(f"problem with file {pdf}")

    except:
            print("cant merge !! sorry")
    else:
            print(f" {pdf} Merged !!! ")

merger.write("Merged_doc.pdf")

在本文中,我使用了PyPDF2.PdfFileMerger和PyPDF2.PdfFileReader,而不是在使用f.close()、exec output.write(outputStream)时将文件名显式转换为文件对象,提示IO错误。老实说,我还没有读到长答案。不过短答案很好。我注意到我无法删除附加的一些文件,使用调用
writer.append(PdfFileReader(file(filename,'rb'))
,创建一个中间
PdfFileReader
对象。即使调用
writer.close()
。更简单的调用
merge.append(文件名为'rb'))
似乎没有同样的问题。如果文件太大,这不会导致内存问题吗?@Nishant与您在内存中创建的任何对象一样,是的。事实上,如果您将单个PDF文件的容量增加到千兆字节,可能会有更好的解决方案。@好的,谢谢,值得知道。一个小实用程序很有趣选择命名为临时文件vs内存的Action是我在这方面看到的一个很好的解决方案。
import sys
import os
import PyPDF2

merger = PyPDF2.PdfFileMerger()

#get PDFs files and path

path = sys.argv[1]
pdfs = sys.argv[2:]
os.chdir(path)


#iterate among the documents
for pdf in pdfs:
    try:
        #if doc exist then merge
        if os.path.exists(pdf):
            input = PyPDF2.PdfFileReader(open(pdf,'rb'))
            merger.append((input))
        else:
            print(f"problem with file {pdf}")

    except:
            print("cant merge !! sorry")
    else:
            print(f" {pdf} Merged !!! ")

merger.write("Merged_doc.pdf")