Mam doświadczenie w C ++ / Obj-C i właśnie odkrywam Python (piszę to od około godziny). Piszę skrypt do rekurencyjnego odczytu zawartości plików tekstowych w strukturze folderów.
Mam problem z tym, że kod, który napisałem, będzie działał tylko w jednym folderze. Rozumiem, dlaczego w kodzie (patrz #hardcoded path
) po prostu nie wiem, jak mogę iść naprzód z Pythonem, ponieważ moje doświadczenie z nim jest zupełnie nowe.
Kod Python:
import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
for folder in subFolders:
outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path
folderOut = open( outfileName, 'w' )
print "outfileName is " + outfileName
for file in files:
filePath = rootdir + '/' + file
f = open( filePath, 'r' )
toWrite = f.read()
print "Writing '" + toWrite + "' to" + filePath
folderOut.write( toWrite )
f.close()
folderOut.close()
os.walk
nie jest zła, chociaż wymyśliłem jeszcze szybszą drogęos.scandir
. Wszystkieglob
rozwiązania są znacznie wolniejsze niżwalk
&scandir
. Moja funkcja, a także pełną analizę prędkości, można znaleźć tutaj: stackoverflow.com/a/59803793/2441026Jeśli używasz języka Python 3.5 lub nowszego, możesz to zrobić w 1 linii.
Jak wspomniano w dokumentacji
Jeśli chcesz każdy plik, możesz użyć
źródło
root_dir
wymaga ukośnika końcowego? Zaoszczędzi to ludziom czasu (a przynajmniej zaoszczędziłoby mi czasu). Dzięki.glob.iglob(root_dir + '**/**', recursive=True)
. Pracuję w Python 3.8.2Zgadzam się z Dave'em Webbem,
os.walk
da przedmiot dla każdego katalogu w drzewie. Faktem jest, że po prostu nie musisz się tym przejmowaćsubFolders
.Taki kod powinien działać:
źródło
TL; DR: Jest to odpowiednik
find -type f
przejścia do wszystkich plików we wszystkich folderach poniżej, łącznie z bieżącym:Jak już wspomniano w innych odpowiedziach,
os.walk()
jest to odpowiedź, ale można ją lepiej wyjaśnić. To całkiem proste! Przejdźmy przez to drzewo:Z tym kodem:
Jest
currentpath
to bieżący folder, na który patrzy. Spowoduje to wygenerowanie:Więc zapętla się trzy razy, ponieważ istnieją trzy foldery: bieżący
docs
ipics
. W każdej pętli wypełnia zmiennefolders
orazfiles
wszystkie foldery i pliki. Pokażmy im:To pokazuje nam:
Więc w pierwszym wierszu widzimy, że jesteśmy w folderze
.
, że zawiera dwa foldery mianowiciepics
idocs
, i że jest jeden plik, mianowicietodo.txt
. Nie musisz nic robić, aby ponownie znaleźć się w tych folderach, ponieważ, jak widzisz, automatycznie się powtarza i po prostu udostępnia pliki w dowolnych podfolderach. I wszelkie podfoldery tego (choć nie mamy ich w tym przykładzie).Jeśli chcesz po prostu przeglądać wszystkie pliki, odpowiednik
find -type f
, możesz to zrobić:To daje:
źródło
pathlib
Biblioteka jest naprawdę wielki dla pracy z plikami. Możesz zrobić rekurencyjną glob na takimPath
obiekcie.źródło
Jeśli chcesz mieć płaską listę wszystkich ścieżek pod danym katalogiem (jak
find .
w powłoce):Aby uwzględnić tylko pełne ścieżki do plików w katalogu podstawowym, pomiń
+ subdirs
.źródło
**/**
służy do rekurencyjnego pobierania wszystkich plików, w tymdirectory
.if os.path.isfile(filename)
służy do sprawdzenia, czyfilename
zmienna jestfile
lubdirectory
, jeśli jest to plik możemy odczytać tego pliku. Tutaj drukuję plik.źródło
Za najłatwiejsze uważam:
Korzystanie
glob('some/path/**', recursive=True)
pobiera wszystkie pliki, ale obejmuje także nazwy katalogów. Dodanieif os.path.isfile(f)
warunku filtruje tę listę tylko do istniejących plikówźródło
użyj,
os.path.join()
aby skonstruować swoje ścieżki - jest ładniejszy:źródło
os.walk
domyślnie wykonuje marsz rekurencyjny. Dla każdego katalogu, zaczynając od katalogu głównego, daje 3-krotki (dirpath, dirnames, nazwy plików)źródło
walk()
Do powrotu rekurencyjnej listę. Próbowałem twojego kodu i dostałem listę z wieloma powtórzeniami ... Jeśli po prostu usuniesz wiersze pod komentarzem „# rekurencyjne wywołania na podfolderach” - działa dobrzeSpróbuj tego:
źródło
Myślę, że problem polega na tym, że nie przetwarzasz
os.walk
poprawnie danych wyjściowych .Po pierwsze zmień:
do:
rootdir
jest twoim stałym katalogiem początkowym;root
to katalog zwrócony przezos.walk
.Po drugie, nie musisz wciskać pętli przetwarzania plików, ponieważ nie ma sensu uruchamiać tego dla każdego podkatalogu. Dostaniesz
root
zestaw do każdego podkatalogu. Nie musisz ręcznie przetwarzać podkatalogów, chyba że chcesz coś zrobić z samymi katalogami.źródło
filePath = rootdir + '/' + file
, co nie brzmi dobrze: plik jest z listy bieżących plików, więc piszesz do wielu istniejących plików?