Подтвердить что ты не робот

Pypdf Объединение нескольких PDF файлов в один PDF файл

Если у меня есть 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 = PdfFileReader(file(filename500+, "rb")),

Сообщение об ошибке: IOError: [Errno 24] Too many open files:

Я думаю, что это ошибка, если нет, что мне делать?

4b9b3361

Ответ 1

Недавно я столкнулся с этой же проблемой, поэтому я впился в 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 (следовательно, указанная ошибка ввода-вывода, если вы закрываете файл). 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):

    if type(fileobj) in (str, unicode):
        fileobj = file(fileobj, 'rb')
        my_file = True
    elif type(fileobj) == file:
        fileobj.seek(0)
        filecontent = fileobj.read()
        fileobj = StringIO(filecontent)
        my_file = True
    elif type(fileobj) == PdfFileReader:
        orig_tell = fileobj.stream.tell()   
        fileobj.stream.seek(0)
        filecontent = StringIO(fileobj.stream.read())
        fileobj.stream.seek(orig_tell)
        fileobj = filecontent
        my_file = True

Мы можем видеть, что параметр append() принимает строку, и при этом принимает это путь к файлу и создает файл-объект в этом месте. Конечным результатом является то же самое, чего мы пытаемся избежать. A PdfFileReader() объект, который открывает файл до тех пор, пока файл не будет написан в конце!

Однако, если мы либо создадим файл-объект строки пути файла, либо объект PdfFileReader (см. Edit 2) строки пути до того, как он будет передан в append(), он будет автоматически создайте копию для нас как объект StringIO, позволяя Python закрыть файл.

Я бы рекомендовал более простой merger.append(file(filename, 'rb')), поскольку другие сообщили, что объект PdfFileReader может оставаться открытым в памяти даже после вызова writer.close().

Надеюсь, это помогло!

EDIT: Я предположил, что вы использовали PyPDF2, а не PyPDF. Если вы этого не сделаете, я настоятельно рекомендую переключиться, поскольку PyPDF больше не поддерживается, когда автор дает свои официальные благословения Phaseit в разработке PyPDF2.

Если по какой-то причине вы не можете поменять местами на PyPDF2 (лицензирование, системные ограничения и т.д.), чем PdfFileMerger не будет доступен вам. В этой ситуации вы можете повторно использовать код из PyPDF2 merge (приведенный выше) для создания копии файла как объекта StringIO и использовать его в своем коде вместо файлового объекта.

РЕДАКТИРОВАТЬ 2: Предыдущая рекомендация использования merger.append(PdfFileReader(file(filename, 'rb'))) изменена на основе комментариев (Спасибо @Agostino).

Ответ 2

Пакет pdfrw читает каждый файл за один раз, поэтому не будет страдать от проблемы с большим количеством открытых файлов. Здесь приведен пример конкатенации script.

Соответствующая часть - предполагает inputs - список входных имен файлов, а outfn - это имя выходного файла:

from pdfrw import PdfReader, PdfWriter

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

Отказ от ответственности: я являюсь основным автором pdfrw.

Ответ 3

Возможно, это просто то, что он говорит, вы открываете для многих файлов. Вы можете явно использовать f=file(filename) ... f.close() в цикле или использовать оператор with. Чтобы каждый открытый файл был правильно закрыт.

Ответ 4

Проблема заключается в том, что вам разрешено открывать определенное количество файлов в любой момент времени. Есть способы изменить это (http://docs.python.org/3/library/resource.html#resource.getrlimit), но я не думаю, что вам это нужно.

Что вы можете попробовать - это закрыть файлы в цикле for:

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