txt - formas de leer un archivo en python
Python concatenar archivos de texto (11)
¿Qué pasa con los comandos de UNIX? (dado que no estás trabajando en Windows):
ls | xargs cat | tee output.txt
ls | xargs cat | tee output.txt
hace el trabajo (puede llamarlo desde python con subproceso si lo desea)
Tengo una lista de 20 nombres de archivos, como [''file1.txt'', ''file2.txt'', ...]
. Quiero escribir un script de Python para concatenar estos archivos en un nuevo archivo. Podría abrir cada archivo por f = open(...)
, leer línea por línea llamando a f.readline()
y escribir cada línea en ese nuevo archivo. No me parece muy "elegante", especialmente la parte donde tengo que leer // escribir línea por línea.
¿Hay alguna forma más "elegante" de hacer esto en Python?
Compruebe el método .read () del objeto Archivo:
http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects
Podrías hacer algo como:
concat = ""
for file in files:
concat += open(file).read()
o una forma de pitón más ''elegante'':
concat = ''''.join([open(f).read() for f in files])
que, de acuerdo con este artículo: http://www.skymind.com/~ocrow/python_string/ también sería el más rápido.
Esto debería hacerlo
Para archivos grandes:
filenames = [''file1.txt'', ''file2.txt'', ...]
with open(''path/to/output/file'', ''w'') as outfile:
for fname in filenames:
with open(fname) as infile:
for line in infile:
outfile.write(line)
Para archivos pequeños:
filenames = [''file1.txt'', ''file2.txt'', ...]
with open(''path/to/output/file'', ''w'') as outfile:
for fname in filenames:
with open(fname) as infile:
outfile.write(infile.read())
... y otra interesante que pensé :
filenames = [''file1.txt'', ''file2.txt'', ...]
with open(''path/to/output/file'', ''w'') as outfile:
for line in itertools.chain.from_iterable(itertools.imap(open, filnames)):
outfile.write(line)
Tristemente, este último método deja algunos descriptores de archivos abiertos, de los cuales el GC debería encargarse de todos modos. Solo pensé que era interesante
No sé sobre elegancia, pero esto funciona:
import glob
import os
for f in glob.glob("file*.txt"):
os.system("cat "+f+" >> OutFile.txt")
Para eso es exactamente la entrada de fileinput :
import fileinput
with open(outfilename, ''w'') as fout, fileinput.input(filenames) as fin:
for line in fin:
fout.write(line)
Para este caso de uso, en realidad no es mucho más simple que simplemente iterar sobre los archivos manualmente, pero en otros casos, tener un único iterador que itere sobre todos los archivos como si fueran un solo archivo es muy útil. (Además, el hecho de que la entrada de fileinput
cierra cada archivo tan pronto como está listo significa que no hay necesidad de close
o close
cada uno, pero eso es solo un ahorro de una línea, no tanto).
Hay otras funciones ingeniosas en la entrada de fileinput
, como la capacidad de realizar modificaciones in situ de archivos simplemente filtrando cada línea.
Como se señaló en los comentarios, y se discutió en otra post , la fileinput
de fileinput
para Python 2.7 no funcionará como se indica. Aquí ligera modificación para que el código Python 2.7 sea compatible
with open(''outfilename'', ''w'') as fout:
fin = fileinput.input(filenames)
for line in fin:
fout.write(line)
fin.close()
Si los archivos no son gigantescos:
with open(''newfile.txt'',''wb'') as newf:
for filename in list_of_files:
with open(filename,''rb'') as hf:
newf.write(hf.read())
# newf.write(''/n/n/n'') if you want to introduce
# some blank lines between the contents of the copied files
Si los archivos son demasiado grandes para leerlos completamente y guardarlos en la memoria RAM, el algoritmo debe ser un poco diferente para leer cada archivo que se va a copiar en un bucle por fragmentos de longitud fija, usando read(10000)
por ejemplo.
Si tiene muchos archivos en el directorio, entonces glob2
podría ser una mejor opción para generar una lista de nombres de archivos en lugar de escribirlos a mano.
import glob2
filenames = glob2.glob(''*.txt'') # list of all .txt files in the directory
with open(''outfile.txt'', ''w'') as f:
for file in filenames:
with open(file) as infile:
f.write(infile.read()+''/n'')
Una alternativa a @ inspectorG4dget respuesta (la mejor respuesta hasta la fecha 29-03-2016). Probé con 3 archivos de 436MB.
@ inspectorG4dget solución: 162 segundos
La siguiente solución: 125 segundos
from subprocess import Popen
filenames = [''file1.txt'', ''file2.txt'', ''file3.txt'']
fbatch = open(''batch.bat'',''w'')
str ="type "
for f in filenames:
str+= f + " "
fbatch.write(str + " > file4results.txt")
fbatch.close()
p = Popen("batch.bat", cwd=r"Drive:/Path/to/folder")
stdout, stderr = p.communicate()
La idea es crear un archivo por lotes y ejecutarlo, aprovechando la "vieja y buena tecnología". Es semi-python pero funciona más rápido. Funciona para windows.
Use shutil.copyfileobj
. Debería ser más eficiente.
with open(''output_file.txt'',''wb'') as wfd:
for f in [''seg1.txt'',''seg2.txt'',''seg3.txt'']:
with open(f,''rb'') as fd:
shutil.copyfileobj(fd, wfd, 1024*1024*10)
#10MB per writing chunk to avoid reading big file into memory.
def concatFiles():
path = ''input/''
files = os.listdir(path)
for idx, infile in enumerate(files):
print ("File #" + str(idx) + " " + infile)
concat = ''''.join([open(path + f).read() for f in files])
with open("output_concatFile.txt", "w") as fo:
fo.write(path + concat)
if __name__ == "__main__":
concatFiles()
outfile.write(infile.read()) 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271s
Un punto de referencia simple muestra que el shutil tiene un mejor rendimiento.