Python concaténer des fichiers texte
j'ai une liste de 20 noms de fichiers, comme ['file1.txt', 'file2.txt', ...]
. Je veux écrire un script Python pour concaténer ces fichiers dans un nouveau fichier. J'ai pu ouvrir chaque fichier par f = open(...)
, lire ligne par ligne, en appelant f.readline()
, et d'écrire chaque ligne dans ce nouveau fichier. Cela ne me semble pas très "élégant", surtout la partie où je dois lire//écrire ligne par ligne.
y a-t-il une façon plus" élégante " de faire cela en Python?
11 réponses
Cela devrait le faire
pour les fichiers volumineux:
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)
pour les petits fichiers:
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())
... et un autre intéressant que j'ai pensé de :
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)
malheureusement, cette dernière méthode laisse quelques descripteurs de fichier ouverts, dont le GC devrait s'occuper de toute façon. J'ai juste pensé que c'était intéressant
utiliser shutil.copyfileobj
. Elle devrait être plus efficace.
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.
C'est exactement ce que fileinput signifie:
import fileinput
with open(outfilename, 'w') as fout, fileinput.input(filenames) as fin:
for line in fin:
fout.write(line)
Pour ce cas d'utilisation, c'est vraiment pas beaucoup plus simple que juste de parcourir les fichiers manuellement, mais dans d'autres cas, un seul itérateur qui parcourt tous les fichiers comme s'ils étaient un seul fichier qui est très pratique. (Aussi, le fait que fileinput
ferme chaque fichier dès que c'est fait y a pas besoin de with
ou close
chacun, mais c'est juste une des économies d'une ligne, pas si importantes que ça.)
il y a d'autres fonctionnalités dans fileinput
, comme la possibilité de faire des modifications en place des fichiers en filtrant chaque ligne.
comme noté dans les commentaires, et discuté dans un autre post , fileinput
pour Python 2.7 ne fonctionnera pas comme indiqué. Ici légère modification pour rendre le code Python conforme 2.7
with open('outfilename', 'w') as fout:
fin = fileinput.input(filenames)
for line in fin:
fout.write(line)
fin.close()
je ne sais pas à propos de l'élégance, mais cela fonctionne:
import glob
import os
for f in glob.glob("file*.txt"):
os.system("cat "+f+" >> OutFile.txt")
Qu'est-ce qui ne va pas avec les commandes UNIX ? (étant donné que vous ne travaillez pas sous Windows) :
ls | xargs cat | tee output.txt
fait le travail ( vous pouvez l'appeler à partir de python avec des sous-processus si vous voulez)
si les fichiers ne sont pas gigantesques:
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 les fichiers sont trop gros pour être entièrement lus et conservés en mémoire vive, l'algorithme doit être un peu différent pour lire chaque fichier à copier en boucle par des morceaux de longueur fixe, en utilisant read(10000)
par exemple.
Si vous avez beaucoup de fichiers dans le répertoire, puis glob2
pourrait être une meilleure option pour générer une liste de noms de fichiers plutôt que de les écrire à la main.
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')
outfile.write(infile.read()) 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271s
un simple benchmark montre que le shutil fonctionne mieux.
.lire () la méthode de L'objet de fichier:
http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects
Vous pourriez faire quelque chose comme:
concat = ""
for file in files:
concat += open(file).read()
ou plus "élégante" python-façon:
concat = ''.join([open(f).read() for f in files])
qui, selon cet article: http://www.skymind.com/~ocrow/ python_string / serait aussi le plus rapide.
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()
une alternative à la réponse @ inspectorG4dget (meilleure réponse à ce jour 29-03-2016). J'ai testé avec 3 fichiers de 436MO.
@inspectorG4dget solution: 162 secondes
la solution suivante : 125 secondes
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()
L'idée est de créer un fichier batch et de l'exécuter, profitant d'une "vieille technologie". Son semi-python fonctionne plus rapidement. Fonctionne pour windows.