Dividir el archivo de texto grande (alrededor de 50 GB) en varios archivos

Me gustaría dividir un archivo de texto grande de alrededor de 50 GB en varios archivos. Los datos en los archivos son así: [x = cualquier entero entre 0-9]

xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx ............... ............... 

Puede haber algunos miles de millones de líneas en el archivo y me gustaría escribir, por ejemplo, 30/40 millones por archivo. Supongo que los pasos serían …

  • Tengo que abrir el archivo
  • luego, utilizando readline (), debe leer el archivo línea por línea y escribir al mismo tiempo en un nuevo archivo
  • y tan pronto como llegue al número máximo de líneas, creará otro archivo y comenzará a escribir de nuevo.

Me pregunto, cómo poner todos estos pasos juntos en una forma eficiente y rápida de memoria. He visto algunos ejemplos en la stack, pero ninguno de ellos ayuda totalmente a lo que necesito exactamente. Realmente apreciaría si alguien pudiera ayudarme.

Esta solución de trabajo utiliza el comando de split disponible en shell. Dado que el autor ya ha aceptado la posibilidad de una solución que no sea de python, por favor no anote el voto.

Primero, creé un archivo de prueba con 1000M entradas (15 GB) con

 awk 'BEGIN{for (i = 0; i < 1000000000; i++) {print "123.123.123.123"} }' > t.txt 

Luego utilicé split :

 split --lines=30000000 --numeric-suffixes --suffix-length=2 t.txt t 

Le tomó 5 minutos producir un conjunto de 34 archivos pequeños con los nombres t00t33 . 33 archivos tienen 458 MB cada uno y el último t33 es 153 MB.

 from itertools import chain, islice def chunks(iterable, n): "chunks(ABCDE,2) => AB CD E" iterable = iter(iterable) while True: # store one line in memory, # chain it to an iterator on the rest of the chunk yield chain([next(iterable)], islice(iterable, n-1)) l = 30*10**6 file_large = 'large_file.txt' with open(file_large) as bigfile: for i, lines in enumerate(chunks(bigfile, l)): file_split = '{}.{}'.format(file_large, i) with open(file_split, 'w') as f: f.writelines(lines) 

Yo usaría la división de la utilidad Unix, si está disponible para usted y su única tarea es dividir el archivo. Aquí hay, sin embargo, una solución pura de Python:

 import contextlib file_large = 'large_file.txt' l = 30*10**6 # lines per split file with contextlib.ExitStack() as stack: fd_in = stack.enter_context(open(file_large)) for i, line in enumerate(fd_in): if not i % l: file_split = '{}.{}'.format(file_large, i//l) fd_out = stack.enter_context(open(file_split, 'w')) fd_out.write('{}\n'.format(line)) 

Si todas sus líneas tienen 4 números de 3 dígitos y tiene varios núcleos disponibles, entonces puede explotar la búsqueda de archivos y ejecutar múltiples procesos.

Esta clase puede resolver su problema. Lo he probado en sistemas operativos Linux y Windows, y ha funcionado perfectamente en ambos. Además, he probado archivos de texto y binarios con diferentes tamaños cada vez y fue genial. Disfrutar 🙂

 import os import math class FileSpliter: # If file type is text then CHUNK_SIZE is count of chars # If file type is binary then CHUNK_SIZE is count of bytes def __init__(self, InputFile, FileType="b", CHUNK_SIZE=524288, OutFile="outFile"): self.CHUNK_SIZE = CHUNK_SIZE # byte or char self.InputFile = InputFile self.FileType = FileType # b: binary, t: text self.OutFile = OutFile self.FileSize = 0 self.Parts = None self.CurrentPartNo = 0 self.Progress = 0.0 def Prepare(self): if not(os.path.isfile(self.InputFile) and os.path.getsize(self.InputFile) > 0): print("ERROR: The file is not exists or empty!") return False self.FileSize = os.path.getsize(self.InputFile) if self.CHUNK_SIZE >= self.FileSize: self.Parts = 1 else: self.Parts = math.ceil(self.FileSize / self.CHUNK_SIZE) return True def Split(self): if self.FileSize == 0 or self.Parts == None: print("ERROR: File is not prepared for split!") return False with open(self.InputFile, "r" + self.FileType) as f: while True: if self.FileType == "b": buf = bytearray(f.read(self.CHUNK_SIZE)) elif self.FileType == "t": buf = f.read(self.CHUNK_SIZE) else: print("ERROR: File type error!") if not buf: # we've read the entire file in, so we're done. break of = self.OutFile + str(self.CurrentPartNo) outFile = open(of, "w" + self.FileType) outFile.write(buf) outFile.close() self.CurrentPartNo += 1 self.ProgressBar() return True def Rebuild(self): self.CurrentPartNo = 0 if self.Parts == None: return False with open(self.OutFile, "w" + self.FileType) as f: while self.CurrentPartNo < self.Parts: If = self.OutFile + str(self.CurrentPartNo) if not(os.path.isfile(If) and os.path.getsize(If) > 0): print("ERROR: The file [" + If + "] is not exists or empty!") return False InputFile = open(If, "r" + self.FileType) buf = InputFile.read() if not buf: # we've read the entire file in, so we're done. break f.write(buf) InputFile.close() os.remove(If) self.CurrentPartNo += 1 self.ProgressBar() return True def ProgressBar(self, BarLength=20, ProgressIcon="#", BarIcon="-"): try: # You can't have a progress bar with zero or negative length. if BarLength <1: BarLength = 20 # Use status variable for going to the next line after progress completion. Status = "" # Calcuting progress between 0 and 1 for percentage. self.Progress = float(self.CurrentPartNo) / float(self.Parts) # Doing this conditions at final progressing. if self.Progress >= 1.: self.Progress = 1 Status = "\r\n" # Going to the next line # Calculating how many places should be filled Block = int(round(BarLength * self.Progress)) # Show this Bar = "\r[{}] {:.0f}% {}".format(ProgressIcon * Block + BarIcon * (BarLength - Block), round(self.Progress * 100, 0), Status) print(Bar, end="") except: print("\rERROR") def main(): fp = FileSpliter(InputFile="inFile", FileType="b") #, CHUNK_SIZE=300000) if fp.Prepare(): # Spliting ... print("Spliting ...") sr = fp.Split() if sr == True: print("The file splited successfully.") print() # Rebuilding ... print("Rebuilding ...") rr = fp.Rebuild() if rr == True: print("The file rebuilded successfully.") if __name__ == "__main__": main()