Dividir un archivo en varios archivos según el patrón (el corte puede ocurrir dentro de las líneas)

Existen muchas soluciones, pero la especificidad aquí es que necesito poder dividirme dentro de una línea, el corte debe ocurrir justo antes del patrón. Ex:

En archivo:

        

Debe hacerse con el patrón <?xml

Outfile1:

      

Outfile2:

     

Outfile3:

  

En realidad, el script perl en la respuesta validada aquí funciona bien para mi pequeño ejemplo. Pero genera un error para mis archivos reales más grandes (alrededor de 6 GB). El error es:

 panic: sv_setpvn called with negative strlen at /home/.../split.pl line 7,  chunk 1. 

No tengo los permisos para comentar, por eso empecé una nueva publicación. Y, finalmente, una solución de Python sería aún más apreciada, ya que la entiendo mejor.

Esto realiza la división sin leer todo en la memoria RAM:

 def files(): n = 0 while True: n += 1 yield open('/output/dir/%d.part' % n, 'w') pat = ' 

Una advertencia: esto no funciona si su patrón se extiende a lo largo de varias líneas (es decir, contiene "\ n"). Considere la solución mmap si este es el caso.

Perl puede analizar grandes archivos línea por línea en lugar de absorber todo el archivo en la memoria. Aquí hay un breve guión (con explicación):

 perl -n -E 'if (/(.*)(<\?xml.*)/ ) { print $fh $1 if $1; open $fh, ">output." . ++$i; print $fh $2; } else { print $fh $_ }' in.txt 

perl -n : la bandera -n se desplazará sobre su línea línea por archivo (configurando el contenido en $ _)

-E : Ejecuta el siguiente texto (Perl espera un nombre de archivo por defecto)

if (/(.*)(<\?xml.*) ) si una línea coincide con divida esa línea (utilizando coincidencias de if (/(.*)(<\?xml.*) ) regulares) en $ 1 y $ 2.

print $fh $1 if $1 Imprime el inicio de la línea en el archivo anterior.

open $fh, ">output.". ++$i; Crea un nuevo identificador de archivo para escribir.

print $fh $2 Imprime el rest de la línea en el nuevo archivo.

} else { print $fn $_ } Si la línea no coincide con simplemente imprímala en el identificador de archivo actual.

Nota: este script asume que su archivo de entrada comienza con .

Para archivos de ese tamaño, probablemente querrá usar el módulo mmap , por lo que no tiene que manejar usted mismo la fragmentación del archivo. De los documentos allí:

Los objetos de archivo asignados en memoria se comportan como cadenas y objetos de archivo. A diferencia de los objetos de cadena normales, sin embargo, estos son mutables. Puede usar objetos mmap en la mayoría de los lugares donde se esperan cadenas; por ejemplo, puede usar el módulo re para buscar a través de un archivo asignado en memoria. Como son mutables, puede cambiar un solo carácter haciendo obj[index] = 'a' , o cambiar una subcadena asignándola a un sector: obj[i1:i2] = '...' . También puede leer y escribir datos a partir de la posición actual del archivo, y seek() través del archivo en diferentes posiciones.

Este es un ejemplo rápido que muestra cómo encontrar cada aparición de en el archivo. Puede escribir los fragmentos en archivos nuevos a medida que avanza, pero no he escrito esa parte.

 import mmap import re # a regex to match the "xml" nodes r = re.compile(r'\<\?xml\s\d+\>') with open('so.txt','r+b') as f: mp = mmap.mmap(f.fileno(),0) for m in r.finditer(mp): # here you can start collecting the starting positions and # writing chunks to new files print m.start() 

acaba de hacer una división en sus términos de búsqueda

 for i,part in enumerate(my_xml_Text_string.split("