Mam listę 20 nazw plików, na przykład ['file1.txt', 'file2.txt', ...]
. Chcę napisać skrypt w języku Python, aby połączyć te pliki w nowy plik. Mógłbym otworzyć każdy plik przez f = open(...)
, przeczytać wiersz po wierszu przez wywołanie f.readline()
i zapisać każdy wiersz w tym nowym pliku. Nie wydaje mi się to zbyt „eleganckie”, zwłaszcza część, w której muszę czytać // pisać wiersz po wierszu.
Czy jest bardziej „elegancki” sposób na zrobienie tego w Pythonie?
python
file-io
concatenation
JJ Beck
źródło
źródło
cat file1.txt file2.txt file3.txt ... > output.txt
. W Pythonie, jeśli nie lubiszreadline()
, jest zawszereadlines()
lub po prosturead()
.cat file1.txt file2.txt file3.txt
polecenie za pomocąsubprocess
module i gotowe. Ale nie jestem pewien, czycat
działa w systemie Windows.with
instrukcji, aby upewnić się, że pliki są poprawnie zamknięte, i iteruj po pliku, aby uzyskać wiersze, zamiast używaćf.readline()
.Odpowiedzi:
To powinno wystarczyć
W przypadku dużych plików:
W przypadku małych plików:
… I kolejny ciekawy, o którym pomyślałem :
Niestety, ta ostatnia metoda pozostawia kilka otwartych deskryptorów plików, którymi i tak powinien się zająć GC. Po prostu pomyślałem, że to interesujące
źródło
Użyj
shutil.copyfileobj
.Automatycznie czyta pliki wejściowe fragment po kawałku dla Ciebie, co jest bardziej wydajne i wczytuje pliki wejściowe i będzie działać, nawet jeśli niektóre pliki wejściowe są zbyt duże, aby zmieścić się w pamięci:
źródło
for i in glob.glob(r'c:/Users/Desktop/folder/putty/*.txt'):
cóż, zastąpiłem instrukcję for, aby uwzględnić wszystkie pliki w katalogu, aleoutput_file
zacząłem rosnąć naprawdę bardzo, jak w setkach GB w bardzo krótkim czasie.Właśnie do tego służy fileinput :
W tym przypadku nie jest to o wiele prostsze niż tylko ręczne iterowanie po plikach, ale w innych przypadkach posiadanie jednego iteratora, który iteruje wszystkie pliki, tak jakby były jednym plikiem, jest bardzo przydatne. (Ponadto fakt, że
fileinput
zamyka każdy plik zaraz po zakończeniu, oznacza, że nie ma takiej potrzebywith
lubclose
każdego z nich, ale to tylko jedna linia oszczędności, a nie taka wielka sprawa).W programie jest kilka innych przydatnych funkcji
fileinput
, takich jak możliwość wykonywania lokalnych modyfikacji plików, po prostu filtrując każdą linię.Jak zauważono w komentarzach i omówiono w innym poście ,
fileinput
Python 2.7 nie będzie działał zgodnie z opisem. Tutaj niewielka modyfikacja, aby kod był zgodny z Pythonem 2.7źródło
fileinput
, że jest to sposób na przekształcenie prostegosys.argv
(lub tego, co zostało jako argumenty pooptparse
/ itp.) W duży wirtualny plik dla trywialnych skryptów i nie myśli o używaniu go do niczego else (tj. gdy lista nie jest argumentami wiersza poleceń). Albo uczą się, ale potem zapominają - odkrywam to na nowo co rok lub dwa…for line in fileinput.input()
nie jest to najlepszy sposób wyboru w tym konkretnym przypadku: OP chce łączyć pliki, a nie czytać je wiersz po wierszu, co jest teoretycznie dłuższym procesem do wykonaniaNie znam elegancji, ale to działa:
źródło
cat
może wziąć listę plików, więc nie ma potrzeby wielokrotnego wywoływania tego. Możesz łatwo to zabezpieczyć dzwoniącsubprocess.check_call
zamiastos.system
Co jest nie tak z poleceniami UNIX? (zakładając, że nie pracujesz w systemie Windows):
ls | xargs cat | tee output.txt
wykonuje zadanie (jeśli chcesz, możesz to wywołać z Pythona z podprocesem)źródło
cat * | tee output.txt
.cat file1.txt file2.txt | tee output.txt
1> /dev/null
na końcu poleceniaProsty test porównawczy pokazuje, że shutil działa lepiej.
źródło
Alternatywa dla odpowiedzi @ inspectorG4dget (najlepsza odpowiedź do tej pory 29-03-2016). Testowałem z 3 plikami po 436 MB.
@ inspectorG4dget rozwiązanie: 162 sekundy
Następujące rozwiązanie: 125 sekund
Chodzi o to, aby utworzyć plik wsadowy i uruchomić go, wykorzystując „starą dobrą technologię”. Jego semi-Python, ale działa szybciej. Działa dla okien.
źródło
Jeśli masz dużo plików w katalogu,
glob2
lepszym rozwiązaniem może być wygenerowanie listy nazw plików, zamiast wpisywania ich ręcznie.źródło
Sprawdź metodę .read () obiektu File:
http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects
Możesz zrobić coś takiego:
lub bardziej „elegancki” sposób w Pythonie:
co zgodnie z tym artykułem: http://www.skymind.com/~ocrow/python_string/ byłoby również najszybsze.
źródło
Jeśli pliki nie są gigantyczne:
Jeśli pliki są zbyt duże, aby można je było w całości odczytać i przechowywać w pamięci RAM, algorytm musi być nieco inny, aby odczytać każdy plik, który ma być skopiowany w pętli przez fragmenty o ustalonej długości,
read(10000)
na przykład.źródło
os.open
ios.read
, ponieważ zwykłyopen
używa opakowań Pythona wokół stdio C, co oznacza 1 lub 2 dodatkowe bufory wchodzące ci w drogę.źródło
źródło