Недавно я наткнулся на это точно такая же проблема, так что я порылся в 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()
действительно принимает строку, и при этом предполагается, что это путь к файлу и создает объект файла в этом месте Конечный результат - это то же самое, чего мы пытаемся избежать. Объект PdfFileReader()
, открывающий файл до тех пор, пока файл не будет написан в конце!
Однако, если мы либо создадим файл-объект строки пути файла , либо a PdfFileReader
(см. Редактировать 2) объект строки пути до он передается в append()
, он автоматически создаст для нас копию как объект StringIO
, что позволит Python закрыть файл.
Я бы рекомендовал более простой merger.append(file(filename, 'rb'))
, так как другие сообщили, что объект PdfFileReader
может оставаться открытым в памяти даже после звонка writer.close()
.
Надеюсь, это помогло!
EDIT: Я предположил, что вы использовали PyPDF2
, а не PyPDF
. Если вы этого не сделаете, я настоятельно рекомендую переключиться, поскольку PyPDF больше не поддерживается, когда автор дает свои официальные благословения Phaseit в разработке PyPDF2.
Если по какой-либо причине вы не можете поменять местами на PyPDF2 (лицензирование, системные ограничения и т. Д.), То PdfFileMerger
будет недоступен для вас. В этой ситуации вы можете повторно использовать код из функции PyPDF2 merge
(см. Выше), чтобы создать копию файла как объект StringIO
и использовать его в своем коде вместо файлового объекта.
EDIT 2: Предыдущая рекомендация использования merger.append(PdfFileReader(file(filename, 'rb')))
изменяется на основе комментариев (Спасибо @Agostino).
Буду честным; Я не прочел длинный ответ. Короткий ответ был велик. – BeReal82
Я заметил, что не удалось удалить некоторые из добавленных файлов, создав промежуточный объект «PdfFileReader» с вызовом 'writer.append (PdfFileReader (файл (имя файла, 'rb'))). Они остаются заблокированными даже после вызова 'writer.close()'. Более простой вызов 'merger.append (file (filename, 'rb'))', похоже, не имеет такой же проблемы. – Agostino
Не будет ли это проблемой памяти, если файлы слишком большие? – Nishant