pdfs pdffilemerger python pypdf

python - pdffilemerger - pypdf2 merge pdfs



pypdf fusionar varios archivos pdf en un pdf (4)

Si tengo más de 1000 archivos pdf, debo combinarlos en un solo 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()

Ejecute el código anterior, cuando input = PdfFileReader(file(filename500+, "rb")) ,

Un mensaje de error: IOError: [Errno 24] Too many open files:

Creo que esto es un error, si no, ¿qué debo hacer?


El paquete pdfrw lee cada archivo de una vez, por lo que no sufrirá el problema de tener demasiados archivos abiertos. Here hay un ejemplo de script de concatenación.

La parte relevante - asume inputs es una lista de nombres de archivos de entrada, y outfn es un nombre de archivo de salida:

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

Descargo de responsabilidad: Soy el principal autor pdfrw.


El problema es que solo se le permite tener un cierto número de archivos abiertos en un momento dado. Hay formas de cambiar esto ( http://docs.python.org/3/library/resource.html#resource.getrlimit ), pero no creo que lo necesite.

Lo que podrías intentar es cerrar los archivos en el bucle for:

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


Hace poco me encontré con el mismo problema, así que busqué en PyPDF2 para ver qué sucede y cómo resolverlo.

Nota: Supongo que el filename es una cadena de ruta de archivo bien formada. Asume lo mismo para todo mi código

La respuesta corta

Use la clase PdfFileMerger() lugar de la clase PdfFileWriter() . He intentado proporcionar lo siguiente para asemejarme lo más posible a tu contenido:

from PyPDF2 import PdfFileMerger, PdfFileReader [...] merger = PdfFileMerger() for filename in filenames: merger.append(PdfFileReader(file(filename, ''rb''))) merger.write("document-output.pdf")

La respuesta larga

La forma en que está utilizando PdfFileReader y PdfFileWriter es mantener cada archivo abierto, y finalmente hace que Python genere IOError 24. Para ser más específico, cuando agrega una página a PdfFileWriter , está agregando referencias a la página en el PdfFileReader abierto ( por lo tanto, el error de E / S observado si cierra el archivo). Python detecta que el archivo sigue siendo referenciado y no realiza ninguna recolección de basura / cierre automático de archivos a pesar de reutilizar el identificador de archivo. Permanecen abiertos hasta que PdfFileWriter ya no necesita acceder a ellos, que se encuentra en output.write(outputStream) en su código.

Para resolver esto, cree copias en la memoria del contenido y permita que se cierre el archivo. Noté en mis aventuras a través del código PyPDF2 que la clase PdfFileMerger() ya tiene esta funcionalidad, así que en lugar de reinventar la rueda, opté por usarla en su lugar. Sin embargo, supe que mi primer vistazo a PdfFileMerger no era lo suficientemente cercano y que solo creaba copias en ciertas condiciones .

Mis intentos iniciales parecían ser los siguientes, y resultaron en los mismos problemas de IO:

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

Mirando el código fuente de PyPDF2, vemos que append() requiere que se pase fileobj , y luego usa la función merge() , pasando la última página como la nueva posición de los archivos. merge() hace lo siguiente con fileobj (antes de abrirlo con 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

Podemos ver que la opción append() acepta una cadena, y al hacerlo, asume que es una ruta de archivo y crea un objeto de archivo en esa ubicación. El resultado final es exactamente lo mismo que intentamos evitar. ¡Un objeto PdfFileReader() que mantiene abierto un archivo hasta que finalmente se escribe!

Sin embargo, si creamos un objeto de archivo de la cadena de ruta de archivo o un objeto PdfFileReader (ver Edición 2) de la cadena de ruta antes de que se pase a append() , automáticamente creará una copia para nosotros como un objeto StringIO , permitiendo Python para cerrar el archivo.

Recomendaría el merger.append(file(filename, ''rb'')) más merger.append(file(filename, ''rb'')) , ya que otros informaron que un objeto PdfFileReader puede permanecer abierto en la memoria, incluso después de llamar a writer.close() .

Espero que esto haya ayudado!

EDITAR: asumí que estaba usando PyPDF2 , no PyPDF . Si no es así, recomiendo encarecidamente el cambio, ya que PyPDF ya no se mantiene con el autor dando sus bendiciones oficiales a Phaseit en el desarrollo de PyPDF2.

Si, por algún motivo, no puede cambiar a PyPDF2 (licencias, restricciones del sistema, etc.), PdfFileMerger no estará disponible para usted. En esa situación, puede reutilizar el código de la función de merge de PyPDF2 (provista arriba) para crear una copia del archivo como un objeto StringIO , y usarlo en su código en lugar del objeto del archivo.

EDIT 2: recomendación previa de usar merger.append(PdfFileReader(file(filename, ''rb''))) modificada según los comentarios (Gracias @Agostino) .


Tal vez justo lo que dice, estás abriendo muchos archivos. Puede usar explícitamente f=file(filename) ... f.close() en el bucle, o usar la instrucción with . Para que cada archivo abierto se cierre correctamente.