Zanurkuj w Pythonie/Praca z katalogami

Praca z katalogami

edytuj

Moduł os.path zawiera kilka funkcji służących do manipulacji plikami i katalogami (w systemie Windows nazywanymi folderami). Przyjrzymy się teraz obsłudze ścieżek i odczytywaniu zawartości katalogów.

Przykład. Tworzenie ścieżek do plików
>>> import os
>>> os.path.join("c:\\music\\ap\\", "mahadeva.mp3")   #(1) (2)
'c:\\music\\ap\\mahadeva.mp3'
>>> os.path.join("c:\\music\\ap", "mahadeva.mp3")     #(3)
'c:\\music\\ap\\mahadeva.mp3'
>>> os.path.expanduser("~")                           #(4)
'c:\\Documents and Settings\\mpilgrim\\My Documents'
>>> os.path.join(os.path.expanduser("~"), "Python")   #(5)
'c:\\Documents and Settings\\mpilgrim\\My Documents\\Python'
  1. os.path jest referencją do modułu, a ten moduł zależy od platformy z jakiej korzystamy. Tak jak getpass niweluje różnice między platformami ustawiając getpass na funkcję odpowiednią dla naszego systemu, tak os ustawia path na moduł specyficzny dla konkretnej platformy.
  2. Funkcja join modułu os.path tworzy ścieżkę dostępu do pliku z jednej lub kilku ścieżek częściowych. W tym przypadku po prostu łączy dwa łańcuchy znaków. (Zauważmy, że w Windowsie musimy używać podwójnych ukośników.)
  3. W tym, trochę bardziej skomplikowanym, przypadku, join dopisze dodatkowy ukośnik do ścieżki przed dołączeniem do niej nazwy pliku. Nie musimy pisać małej, głupiej funkcji addSlashIfNecessary, ponieważ mądrzy ludzie zrobili już to za nas.
  4. expanduser rozwinie w ścieżce znak ~ na ścieżkę katalogu domowego aktualnie zalogowanego użytkownika. Ta funkcja działa w każdym systemie, w którym użytkownicy mają swoje katalogi domowe, między innymi w systemach Windows, UNIX i Mac OS X, ale w systemie Mac OS nie otrzymujemy żadnych efektów.
  5. Używając tych technik, możemy łatwo tworzyć ścieżki do plików i katalogów wewnątrz katalogu domowego.
Przykład. Rozdzielanie ścieżek
>>> os.path.split("c:\\music\\ap\\mahadeva.mp3")                        #(1)
('c:\\music\\ap', 'mahadeva.mp3')
>>> (filepath, filename) = os.path.split("c:\\music\\ap\\mahadeva.mp3") #(2)
>>> filepath                                                            #(3)
'c:\\music\\ap'
>>> filename                                                            #(4)
'mahadeva.mp3'
>>> (shortname, extension) = os.path.splitext(filename)                 #(5)
>>> shortname
'mahadeva'
>>> extension
'.mp3'
  1. Funkcja split dzieli pełną ścieżkę i zwraca krotkę, która zawiera ścieżkę do katalogu i nazwę pliku. Pamiętasz, jak mówiliśmy, że można używać wielozmiennego przypisania do zwracania kilku wartości z funkcji? split jest taką właśnie funkcją.
  2. Przypisujesz wynik działania funkcji split do krotki dwóch zmiennych. Każda zmienna będzie teraz zawierać wartość odpowiedniego elementu krotki zwróconej przez funkcję split.
  3. Pierwsza zmienna, filepath, zawiera pierwszy element zwróconej listy -- ścieżkę pliku.
  4. Druga zmienna, filename, zawiera drugi element listy -- nazwę pliku.
  5. Moduł os.path zawiera też funkcję splitext, która zwraca krotkę zawierającą właściwą nazwę pliku i jego rozszerzenie. Używamy tej samej techniki, co poprzednio, do przypisania każdej części do osobnej zmiennej.
Przykład. Wyświetlanie zawartości katalogu
>>> os.listdir("c:\\music\\_singles\\")                #(1)
['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3', 
'spinning.mp3']
>>> dirname = "c:\\"
>>> os.listdir(dirname)                                #(2)
['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'cygwin',
'docbook', 'Documents and Settings', 'Incoming', 'Inetpub', 'IO.SYS',
'MSDOS.SYS', 'Music', 'NTDETECT.COM', 'ntldr', 'pagefile.sys',
'Program Files', 'Python20', 'RECYCLER',
'System Volume Information', 'TEMP', 'WINNT']
>>> [f for f in os.listdir(dirname)
...     if os.path.isfile(os.path.join(dirname, f))]   #(3)
['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'IO.SYS', 'MSDOS.SYS',
'NTDETECT.COM', 'ntldr', 'pagefile.sys']
>>> [f for f in os.listdir(dirname)
...     if os.path.isdir(os.path.join(dirname, f))]    #(4)
['cygwin', 'docbook', 'Documents and Settings', 'Incoming',
'Inetpub', 'Music', 'Program Files', 'Python20', 'RECYCLER',
'System Volume Information', 'TEMP', 'WINNT']
  1. Funkcja listdir pobiera ścieżkę do katalogu i zwraca listę jego zawartości.
  2. listdir zwraca zarówno pliki jak i katalogi, bez wskazania które są którymi.
  3. Możemy użyć filtrowania listy i funkcji isfile modułu os.path, aby oddzielić pliki od katalogów. isfile przyjmuje ścieżkę do pliku i zwraca True, jeśli reprezentuje ona plik albo False w innym przypadku. W przykładzie używamy os.path.join, aby uzyskać pełną ścieżkę, ale isfile pracuje też ze ścieżkami względnymi wobec bieżącego katalogu. Możemy użyć os.getcwd() aby pobrać bieżący katalog.
  4. os.path zawiera też funkcję isdir, która zwraca True, jeśli ścieżka reprezentuje katalog i False w innym przypadku. Możemy jej użyć do uzyskania listy podkatalogów.
Przykład. Listowanie zawartości katalogu w fileinfo.py
def listDirectory(directory, fileExtList):
    u"zwraca listę obiektów zawierających metadane dla plików o podanych rozszerzeniach"
    fileList = [os.path.normcase(f) for f in os.listdir(directory)]    #(1) (2)
    fileList = [os.path.join(directory, f) for f in fileList
                if os.path.splitext(f)[1] in fileExtList]              #(3) (4) (5)
  1. os.listdir(directory) zwraca listę wszystkich plików i podkatalogów w katalogu directory.
  2. Iterując po liście z użyciem zmiennej f, wykorzystujemy os.path.normcase(f), aby znormalizować wielkość liter zgodnie z domyślną wielkością liter w systemem operacyjnym. Funkcja normcase jest użyteczną, prostą funkcją, która stanowi równoważnik pomiędzy systemami operacyjnymi, w których wielkość liter w nazwie pliku nie ma znaczenia, w którym np. mahadeva.mp3 i mahadeva.MP3 są takimi samymi plikami. Na przykład w Windowsie i Mac OS, normcase będzie konwertował całą nazwę pliku na małe litery, a w systemach kompatybilnych z UNIX-em funkcja ta będzie zwracała niezmienioną nazwę pliku.
  3. Iterując ponownie po liście z użyciem f, wykorzystujemy os.path.splitext(f), aby podzielić nazwę pliku na nazwę i jej rozszerzenie.
  4. Dla każdego pliku sprawdzamy, czy rozszerzenie jest w liście plików, o które nam chodzi (czyli fileExtList, która została przekazana do listDirectory).
  5. Dla każdego pliku, który nas interesuje, wykorzystujemy os.path.join(directory, f), aby skonstruować pełną ścieżkę pliku i zwrócić listę zawierającą pełne ścieżki.

Jest jeszcze inna metoda dostania się do zawartości katalogu. Metoda ta jest bardzo potężna i używa zestawu symboli wieloznacznych (ang. wildcard), z którymi można się spotkać pracując w linii poleceń.

Przykład. Listowanie zawartości katalogu przy pomocy glob
>>> os.listdir("c:\\music\\_singles\\")               #(1)
['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3',
'spinning.mp3']
>>> import glob
>>> glob.glob('c:\\music\\_singles\\*.mp3')           #(2)
['c:\\music\\_singles\\a_time_long_forgotten_con.mp3',
'c:\\music\\_singles\\hellraiser.mp3',
'c:\\music\\_singles\\kairo.mp3',
'c:\\music\\_singles\\long_way_home1.mp3',
'c:\\music\\_singles\\sidewinder.mp3',
'c:\\music\\_singles\\spinning.mp3']
>>> glob.glob('c:\\music\\_singles\\s*.mp3')          #(3)
['c:\\music\\_singles\\sidewinder.mp3',
'c:\\music\\_singles\\spinning.mp3']
>>> glob.glob('c:\\music\\*\\*.mp3')                  #(4)
  1. Jak wcześniej powiedzieliśmy, os.listdir pobiera ścieżkę do katalogu i zwraca wszystkie pliki i podkatalogi, które się w nim znajdują.
  2. Z drugiej strony, moduł glob na podstawie podanego wyrażenia składającego się z symboli wieloznacznych, zwraca pełne ścieżki wszystkich plików, które spełniają te wyrażenie. Tutaj wyrażenie jest ścieżką do katalogu plus "*.mp3", który będzie dopasowywał wszystkie pliki .mp3. Dodajmy, że każdy element zwracanej listy jest już pełną ścieżką do pliku.
  3. Jeśli chcemy znaleźć wszystkie pliki w określonym katalogu, gdzie nazwa zaczyna się od "s", a kończy na ".mp3", możemy to zrobić w ten sposób.
  4. Teraz rozważ taki scenariusz: mamy katalog z muzyką z kilkoma podkatalogami, wewnątrz których są pliki .mp3. Możemy pobrać listę wszystkich tych plików za pomocą jednego wywołania glob, wykorzystując połączenie dwóch wyrażeń. Pierwszym jest "*.mp3" (wyszukuje pliki .mp3), a drugim są same w sobie ścieżki do katalogów, aby przetworzyć każdy podkatalog w c:\music. Ta prosto wyglądająca funkcja daje nam niesamowite możliwości!

Materiały dodatkowe

edytuj