Python Å‚Ä…czy pliki tekstowe

Mam listę 20 nazw plików, jak ['file1.txt', 'file2.txt', ...]. Chcę napisać skrypt Pythona, aby połączyć te pliki w nowy plik. Mogłem otworzyć KAŻDY plik przez f = open(...), odczytać linię po linii przez wywołanie f.readline() i zapisać każdą linię do tego nowego pliku. Nie wydaje mi się to zbyt "eleganckie", szczególnie część, w której muszę czytać//pisać wiersz po wierszu.

Czy jest bardziej "elegancki" sposób, aby to zrobić w Pythonie?

Author: inspectorG4dget, 2012-11-28

11 answers

This should do it

Dla dużych plików:

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)

Dla małych plików:

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

... i jeszcze jeden ciekawy, o którym myślałem :

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)

Niestety, ta ostatnia metoda pozostawia kilka otwartych deskryptorów plików, którymi i tak powinien zająć się GC. Po prostu myślałem, że to ciekawe

 187
Author: inspectorG4dget,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 06:06:39

Użyj shutil.copyfileobj. Powinno być bardziej wydajne.

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
Author: Meow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 09:03:47

Właśnie do tego służy fileinput:

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

W tym przypadku nie jest to dużo prostsze niż tylko iterowanie plików ręcznie, ale w innych przypadkach posiadanie pojedynczego iteratora, który iterauje wszystkie pliki tak, jakby były pojedynczym plikiem, jest bardzo przydatne. (Również fakt, że fileinput zamyka każdy plik tak szybko, jak to jest zrobione, oznacza, że nie ma potrzeby with lub close każdego z nich, ale to tylko oszczędności w jednej linii, nic wielkiego.)

Są pewne inne sprytne funkcje w fileinput, takie jak możliwość wprowadzania zmian w plikach poprzez filtrowanie każdej linii.


Jak zaznaczono w komentarzach i omówiono w innym poście, fileinput dla Pythona 2.7 nie będzie działać zgodnie ze wskazaniami. Tutaj niewielka modyfikacja, aby kod Python 2.7 zgodny

with open('outfilename', 'w') as fout:
    fin = fileinput.input(filenames)
    for line in fin:
        fout.write(line)
    fin.close()
 45
Author: abarnert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 08:27:14

Nie znam się na elegancji, ale to działa:

    import glob
    import os
    for f in glob.glob("file*.txt"):
         os.system("cat "+f+" >> OutFile.txt")
 7
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-03 01:39:23

Co jest nie tak z poleceniami Uniksa ? (biorąc pod uwagę, że nie działa na Windows):

ls | xargs cat | tee output.txt wykonuje zadanie (możesz wywołać je z Pythona z podprocesem, jeśli chcesz)

 4
Author: lucasg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-28 20:00:34

Jeśli pliki nie są gigantyczne:

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

Jeśli pliki są zbyt duże, aby mogły być całkowicie odczytane i przechowywane w pamięci RAM, algorytm musi być nieco inny, aby odczytać każdy plik do skopiowania w pętli przez kawałki o stałej długości, na przykład za pomocą read(10000).

 1
Author: eyquem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-28 20:04:38

Jeśli masz wiele plików w katalogu, to glob2 może być lepszą opcją do generowania listy nazw plików, zamiast pisania ich ręcznie.

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
Author: Sharad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-06 10:34:57
outfile.write(infile.read()) 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) 0.60599684715271s

Prosty benchmark pokazuje, że szutil działa lepiej.

 1
Author: haoming,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-26 08:10:36

Zobacz teżmetoda read () obiektu File:

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

Możesz zrobić coś takiego:

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

Lub bardziej "elegancki" sposób python:

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

Które zgodnie z tym artykułem: http://www.skymind.com / ~ ocrow / python_string / również byłby najszybszy.

 0
Author: Alex Kawrykow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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
Author: user2825287,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-28 00:03:01

Alternatywa dla odpowiedzi @ inspectorG4dget (najlepsza odpowiedź na dzień 29-03-2016). Testowałem z 3 plikami po 436MB.

@inspectorG4dget rozwiÄ…zanie: 162 sekund

Następujące rozwiązanie: 125 sekund

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

Chodzi o to, aby utworzyć plik wsadowy i wykonać go, wykorzystując "starą dobrą technologię". Jego pół-python, ale działa szybciej. Działa na windows.

 0
Author: João Palma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-30 02:23:12