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 fileinput
elk bestand sluit zodra het is gedaan, betekent dat het niet nodig heeft with
of close
Iedereen, 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 , fileinput
VOOR 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.txt
doet 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 glob2
misschien 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)