Hoe concateneer ik tekstbestanden in Python?

Ik heb een lijst met 20 bestandsnamen, zoals ['file1.txt', 'file2.txt', ...]. Ik wil een Python-script schrijven om deze bestanden aan te voegen in een nieuw bestand. Ik zou elk bestand kunnen openen met f = open(...), leeslijn per regel door f.readline()te bellen en elke regel in dat nieuwe bestand in te schrijven. Het lijkt mij niet erg “elegant”, vooral het deel waar ik regelmatig moet lezen / schrijven / schrijven.

Is er een meer “elegante” manier om dit in Python te doen?


Antwoord 1, Autoriteit 100%

Dit zou het moeten doen

voor grote bestanden:

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)

voor kleine bestanden:

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())

… en een andere interessante die ik heb gedacht :

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)

Helaas laat deze laatste methode een paar open bestandsdescriptoren achter, die de GC hoe dan ook zou moeten zorgen. Ik dacht dat het interessant was


Antwoord 2, Autoriteit 77%

Gebruik shutil.copyfileobj.

Het leest automatisch de ingangsbestanden van Chunk door Chunk voor u, die meer efficiënter is en de invoerbestanden in het lezen is en zal werken, zelfs als sommige invoerbestanden te groot zijn om in het geheugen te passen:

import shutil
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)

Antwoord 3, Autoriteit 22%

Dat is precies wat FILEINPUT is voor:

import fileinput
with open(outfilename, 'w') as fout, fileinput.input(filenames) as fin:
    for line in fin:
        fout.write(line)

Voor dit gebruik is het echt niet veel eenvoudiger dan alleen het handmatig over de bestanden, maar in andere gevallen, met een enkele iterator dat herhaalt over alle bestanden alsof ze een enkel bestand was erg handig. (Ook het feit dat fileinputelk bestand sluit zodra het is gedaan, betekent dat het niet nodig heeft withof closeIedereen, maar dat is gewoon een besparing van één lijn, niet zo’n groot deel.)

Er zijn enkele andere handige functies in fileinput, zoals de mogelijkheid om in de plaatselijke wijzigingen van bestanden te doen door elke regel te filteren.


Zoals opgemerkt in de opmerkingen, en besproken in een andere post , fileinputVOOR PYTHON 2.7 Werkt niet zoals aangegeven. Hier een kleine wijziging om de Code Python 2.7 Compliant

te maken

with open('outfilename', 'w') as fout:
    fin = fileinput.input(filenames)
    for line in fin:
        fout.write(line)
    fin.close()

Antwoord 4, Autoriteit 3%

Ik weet het niet van elegantie, maar dit werkt:

   import glob
    import os
    for f in glob.glob("file*.txt"):
         os.system("cat "+f+" >> OutFile.txt")

Antwoord 5, Autoriteit 2%

Wat is er mis met UNIX-commando’s? (aangezien u niet onder Windows werkt) :

ls | xargs cat | tee output.txtdoet het werk (je kunt het desgewenst vanuit Python met subproces aanroepen)


Antwoord 6, autoriteit 2%

outfile.write(infile.read()) # time: 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) # time: 0.60599684715271s

Een simpele benchmark laat zien dat de Shutil beter presteert.


Antwoord 7

Een alternatief voor @inspectorG4dget antwoord (beste antwoord tot nu toe 29-03-2016). Ik heb getest met 3 bestanden van 436 MB.

@inspectorG4dget oplossing: 162 seconden

De volgende oplossing: 125 seconden

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()

Het idee is om een ​​batchbestand te maken en uit te voeren, gebruikmakend van “oude goede technologie”. Zijn semi-python maar werkt sneller. Werkt voor ramen.


Antwoord 8

Bekijk de .read() methode van het File-object:

http://docs.python.org/ 2/tutorial/inputoutput.html#methods-of-file-objects

Je zou zoiets kunnen doen:

concat = ""
for file in files:
    concat += open(file).read()

of een meer ‘elegante’ python-manier:

concat = ''.join([open(f).read() for f in files])

die volgens dit artikel: http://www.skymind.com/~ocrow/ python_string/zou ook de snelste zijn.


Antwoord 9

Als de bestanden niet gigantisch zijn:

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

Als de bestanden te groot zijn om volledig te worden gelezen en in het RAM-geheugen te worden bewaard, moet het algoritme een beetje anders zijn om elk bestand te lezen dat in een lus moet worden gekopieerd in brokken van vaste lengte, met behulp van read(10000)bijvoorbeeld.


Antwoord 10

Als je veel bestanden in de directory hebt, is glob2misschien een betere optie om een ​​lijst met bestandsnamen te genereren in plaats van ze met de hand te schrijven.

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')

Antwoord 11

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()

Antwoord 12

 import os
  files=os.listdir()
  print(files)
  print('#',tuple(files))
  name=input('Enter the inclusive file name: ')
  exten=input('Enter the type(extension): ')
  filename=name+'.'+exten
  output_file=open(filename,'w+')
  for i in files:
    print(i)
    j=files.index(i)
    f_j=open(i,'r')
    print(f_j.read())
    for x in f_j:
      outfile.write(x)

Other episodes