2009-07-17 31 views
8

Tengo un gran archivo xml (40 Gb) que necesito dividir en trozos más pequeños. Estoy trabajando con espacio limitado, entonces ¿hay alguna manera de eliminar líneas del archivo original cuando las escribo en archivos nuevos?Cambiar el archivo de Python en su lugar

Gracias!

+0

Lo sentimos, no entiendo de qué se trata . –

+1

Corrígeme si me equivoco, pero está intentando dividir un archivo muy grande en partes más pequeñas. Sin embargo, dado que el archivo es tan grande, ya que crea particiones, necesita eliminar esa parte del archivo original para ahorrar espacio. –

+0

@Jesse - Eso es correcto. – AlbertoPL

Respuesta

7

decir que quiere dividir el archivo en piezas N, entonces simplemente comenzar a leer desde la parte posterior del archivo (más o menos) y repetidamente llaman truncate:

truncar el tamaño del archivo. Si el argumento de tamaño opcional está presente, el archivo se trunca a (como máximo) ese tamaño. El tamaño predeterminado es la posición actual. La posición actual del archivo no se cambia. ...

import os 
import stat 

BUF_SIZE = 4096 
size = os.stat("large_file")[stat.ST_SIZE] 
chunk_size = size // N 
# or simply set a fixed chunk size based on your free disk space 
c = 0 

in_ = open("large_file", "r+") 

while size > 0: 
    in_.seek(-min(size, chunk_size), 2) 
    # now you have to find a safe place to split the file at somehow 
    # just read forward until you found one 
    ... 
    old_pos = in_.tell() 
    with open("small_chunk%2d" % (c,), "w") as out: 
     b = in_.read(BUF_SIZE) 
     while len(b) > 0: 
      out.write(b) 
      b = in_.read(BUF_SIZE) 
    in_.truncate(old_pos) 
    size = old_pos 
    c += 1 

tener cuidado, ya que no he probado nada de esto. Podría ser necesario llamar al flush después de la llamada truncada, y no sé qué tan rápido el sistema de archivos realmente liberará el espacio.

+0

Gracias por toda la entrada. Voy a probar algunas de tus sugerencias esta noche. – Maulin

+2

Buena suerte con eso :) –

+0

Nice detail. No hago suficiente Python para poder sacar algo como esto de la parte superior de mi cabeza. – NoMoreZealots

1

Estoy bastante seguro de que hay, como incluso he podido editar/leer de los archivos fuente de los scripts que he ejecutado, pero el mayor problema probablemente sería todo el cambio que se haría si comenzó al principio del archivo. Por otro lado, si revisa el archivo y registra todas las posiciones iniciales de las líneas, puede ir en el orden inverso de la posición para copiar las líneas; Una vez hecho esto, puede volver atrás, tomar los nuevos archivos, uno a la vez, y (si son lo suficientemente pequeños), usar readlines() para generar una lista, invertir el orden de la lista y luego buscar el comienzo del archivo y sobrescribe las líneas en su orden anterior con las líneas en su nuevo.

(Truncaría el archivo después de leer el primer bloque de líneas al final usando el método truncate(), que trunca todos los datos más allá de la posición actual del archivo si se usa sin ningún argumento además del del objeto de archivo, asumiendo que ' Puede usar una de las clases o una subclase de una de las clases del paquete io para leer su archivo. Simplemente debe asegurarse de que la posición actual del archivo termine al principio de la última línea para escribir en un archivo. nuevo archivo.)

EDIT: con base en su comentario sobre tener que hacer las separaciones en las etiquetas de cierre correctas, probablemente también tendrá que desarrollar un algoritmo para detectar dichas etiquetas (quizás usando el método peek), posiblemente usando una expresión regular.

2

Si está en Linux/Unix, ¿por qué no utilizar el comando dividir como this guy?

split --bytes=100m /input/file /output/dir/prefix 

EDITAR: luego usa csplit.

+1

Esto no funcionaría ya que tengo un archivo xml. Necesitaría que cada archivo se divida en la ubicación correcta (después de un registro completo con etiquetas de cierre). – Maulin

+0

@Maulin. ouch ... hace un problema interesante aunque –

0

Si el tiempo no es un factor importante (o el desgaste de la unidad de disco):

  1. identificador abierto en el archivo
  2. leer hasta el tamaño de su partición punto de ruptura/lógica (debido a el xml)
  3. ahorro el resto de su archivo en el disco (no sé cómo pitón maneja este archivo o sobrescribir el uso de memoria por lo que directamente)
  4. Escribir la partición en el disco
  5. Goto 1

Si Python no le da este nivel de control, puede que tenga que sumergirse en C.

-1

¡Es hora de comprar un nuevo disco duro!

Puede hacer copia de seguridad antes de intentar todas las demás respuestas y no obtener los datos perdidos :)

0

Aquí es mi guión ...

import string 
import os 
from ftplib import FTP 

# make ftp connection 
ftp = FTP('server') 
ftp.login('user', 'pwd') 
ftp.cwd('/dir') 

f1 = open('large_file.xml', 'r') 

size = 0 
split = False 
count = 0 

for line in f1: 
    if not split: 
    file = 'split_'+str(count)+'.xml' 
    f2 = open(file, 'w') 
    if count > 0: 
     f2.write('<?xml version="1.0"?>\n') 
     f2.write('<StartTag xmlns="http://www.blah/1.2.0">\n') 
    size = 0 
    count += 1 
    split = True  
    if size < 1073741824: 
     f2.write(line) 
     size += len(line) 
    elif str(line) == '</EndTag>\n': 
     f2.write(line) 
     f2.write('</EndEndTag>\n') 
     print('completed file %s' %str(count)) 
     f2.close() 
     f2 = open(file, 'r') 
     print("ftp'ing file...") 
     ftp.storbinary('STOR ' + file, f2) 
     print('ftp done.') 
     split = False 
     f2.close() 
     os.remove(file) 
    else: 
    f2.write(line) 
    size += len(line) 
Cuestiones relacionadas