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?

112
demandé sur inspectorG4dget 2012-11-28 23:54:46

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

187
répondu inspectorG4dget 2013-08-16 06:06:39

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.
128
répondu Meow 2015-06-17 09:03:47

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()
45
répondu abarnert 2016-09-23 08:27:14

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")
7
répondu Daniel 2014-06-03 01:39:23

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)

4
répondu lucasg 2012-11-28 20:00:34

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.

1
répondu eyquem 2012-11-28 20:04:38

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')
1
répondu Sharad 2017-05-06 10:34:57
outfile.write(infile.read()) 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271s

un simple benchmark montre que le shutil fonctionne mieux.

1
répondu haoming 2018-04-26 08:10:36

.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.

0
répondu Alex Kawrykow 2012-11-28 20:04:20
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()
0
répondu user2825287 2013-09-28 00:03:01

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.

0
répondu João Palma 2016-03-30 02:23:12