13. Operacje na plikach i katalogach

Jednym z podstawowych zadań systemu operacyjnego jest obsługa dyskowego systemu plików. Na poprzedniej lekcji omówiono funkcje Pythona służące do obsługi plików jako zbiorów danych, ich tworzenia i modyfikacji. W tym podrozdziale zostaną omówione funkcje służące do manipulacji plikami w całości, ich przenoszenia i usuwania oraz funkcje obsługujące katalogi dyskowe.

Funkcje, którymi będziemy się zajmować zawarte są w module standardowym os:

 

>>> from os import *

 

Aby sprawdzić, w jakim działamy obecnie katalogu dyskowym używamy funkcji getcwd:

 

>>> getcwd()

'C:\\Python24'

 

Aby zmienić bieżący katalog dyskowy na inny, używamy funkcji chdir(nowy katalog):

 

>>> chdir('tcl')

>>> getcwd()

'C:\\Python24\\tcl'

 

Aby poznać zawartość dowolnego katalogu dyskowego, używamy funkcji listdir(katalog); dla bieżącego katalogu:

 

>>> listdir('.')

['tcl84.lib', 'tclstub84.lib', 'tix8184.lib', 'tk84.lib', 'tkstub84.lib', 'tk8.4', 'tix8.1', 'tcl8.4', 'reg1.1', 'dde1.2']

 

Dla podkatalogu 'tcl8.4':

 

>>> listdir('tcl8.4')

['auto.tcl', 'history.tcl', 'init.tcl', 'ldAout.tcl', 'package.tcl', 'parray.tcl', 'safe.tcl', 'tclIndex', 'word.tcl', 'tcltest2.2', 'opt0.4', 'msgcat1.3', 'http2.4', 'http1.0', 'encoding']

 

Oczywiście, równie dobrze możemy podać ścieżkę absolutną katalogu:

 

>>> listdir(r'C:\Python24\tcl\tcl8.4')

['auto.tcl', 'history.tcl', 'init.tcl', 'ldAout.tcl', 'package.tcl', 'parray.tcl', 'safe.tcl', 'tclIndex', 'word.tcl', 'tcltest2.2', 'opt0.4', 'msgcat1.3', 'http2.4', 'http1.0', 'encoding']

 

Aby filtrować pliki i katalogi według określonego wzorca, musimy posłużyć się funkcją fnmatch(nazwa, wzorzec) z modułu fnmatch. Funkcja ta zwraca prawdę, wtedy i tylko wtedy, gdy nazwa odpowiada wzorcowi:

 

>>> import fnmatch

>>> fnmatch.fnmatch('Python','P*n')

True

>>> fnmatch.fnmatch('Python','P*e')

False

 

Lista plików z rozszerzeniem ‘tcl’:

 

>>> [x for x in listdir(r'C:\Python24\tcl\tcl8.4') if \

fnmatch.fnmatch(x,'*.tcl')]

['auto.tcl', 'history.tcl', 'init.tcl', 'ldAout.tcl', 'package.tcl', 'parray.tcl', 'safe.tcl', 'word.tcl']

 

Lista plików o nazwach kończących się na ‘t’ lub ‘y’:

 

>>> [x for x in listdir(r'C:\Python24\tcl\tcl8.4') if \

fnmatch.fnmatch(x,'*[ty].*')]

['history.tcl', 'init.tcl', 'ldAout.tcl', 'parray.tcl']

 

Zbliżony rezultat otrzymamy używając funkcji glob z modułu glob:

 

>>> for x in glob.glob(r'C:\Python24\tcl\tcl8.4\*[ty].*'):

     print x

    

C:\Python24\tcl\tcl8.4\history.tcl

C:\Python24\tcl\tcl8.4\init.tcl

C:\Python24\tcl\tcl8.4\ldAout.tcl

C:\Python24\tcl\tcl8.4\parray.tcl

 

Jak widać, ścieżki do znalezionych obiektów dyskowych zwracane są w takiej postaci, w jakiej podano jej we wzorcu (w tym przypadku absolutne). Aby rozdzielić ścieżkę absolutną na katalog zawierający plik i nazwę pliku używamy funkcji path.split:

 

>>> path.split('C:\Python24\tcl\tcl8.4\history.tcl')

('C:\\Python24\tcl\tcl8.4', 'history.tcl')

>>> for x in glob.glob(r'tcl8.4\*[ty].*'):

     print path.split(x)[1]

 

    

history.tcl

init.tcl

ldAout.tcl

parray.tcl

 

Funkcja path.join łączy ciąg katalogów w ścieżkę:

 

>>> path.join('C:','Python24','tcl','tcl8.4','history.tcl')

'C:Python24\\tcl\\tcl8.4\\history.tcl'

>>> path.join(r'C:\Python24','tcl','tcl8.4\history.tcl')

'C:\\Python24\\tcl\\tcl8.4\\history.tcl'

 

Funkcja path.isabs sprawdza, czy podana ścieżka jest absolutna:

 

>>> path.isabs(r'tcl8.4\history.tcl')

False

>>> path.isabs(r'C:\Python24\tcl\tcl8.4\history.tcl')

True

 

Funkcja path.exists sprawdza, czy dany obiekt dyskowy istnieje:

 

>>> path.exists('C:\\Python24\\tcl\\tcl8.4\\history.tcl')

True

>>> path.exists('C:\\Python24\\tcl\\nowy')

False

 

Funkcja mkdir(nazwa katalogu) tworzy na dysku nowy katalog:

 

>>> mkdir('nowy')

>>> path.exists('C:\\Python24\\tcl\\nowy')

True

>>> listdir('.')

['tcl84.lib', 'tclstub84.lib', 'tix8184.lib', 'tk84.lib', 'tkstub84.lib', 'tk8.4', 'tix8.1', 'tcl8.4', 'reg1.1', 'dde1.2', 'nowy']

 

Funkcja rename(dotychczasowa nazwa, nowa nazwa) zmienia nazwę pliku lub katalogu:

 

>>> rename('stary','nowy')

>>> path.exists('C:\\Python24\\tcl\\nowy')

False

>>> listdir('.')

['tcl84.lib', 'tclstub84.lib', 'tix8184.lib', 'tk84.lib', 'tkstub84.lib', 'tk8.4', 'tix8.1', 'tcl8.4', 'reg1.1', 'dde1.2', 'stary']

 

Może także służyć do przenoszenia obiektów dyskowych pomiędzy katalogami:

 

>>> file('plik','w').close()

>>> listdir('.')

['tcl84.lib', 'tclstub84.lib', 'tix8184.lib', 'tk84.lib', 'tkstub84.lib', 'tk8.4', 'tix8.1', 'tcl8.4', 'reg1.1', 'dde1.2', 'stary', 'plik']

>>> rename('plik',r'stary\plik')

>>> path.exists('C:\\Python24\\tcl\\plik')

False

>>> path.exists('C:\\Python24\\tcl\\stary\\plik')

True

>>> rename(r'stary\plik','plik')

>>> path.exists('C:\\Python24\\tcl\\stary\\plik')

False

>>> path.exists('C:\\Python24\\tcl\\plik')

True

 

Funkcja path.isfile sprawdza, czy dany obiekt dyskowy jest plikiem:

 

>>> path.isfile('stary')

False

>>> path.isfile('plik')

True

 

Funkcja path.isdir sprawdza, czy dany obiekt dyskowy jest katalogiem:

 

>>> path.isdir('plik')

False

>>> path.isdir('stary')

True

 

Funkcja path.ismount sprawdza, czy dany obiekt dyskowy jest dyskiem:

 

>>> path.ismount('stary')

False

>>> path.ismount('C:\\')

True

 

Funkcja path.getsize zwraca długość pliku w bajtach:

>>> path.getsize('plik')

0L

>>> f=file('plik','w'); f.write('Siedem!'); f.close()

>>> path.getsize('plik')

7L

>>> f=file('plik','w'); f.write('*'*100); f.close()

>>> path.getsize('plik')

100L

 

Dla katalogów zwracane jest zawsze zero:

 

>>> path.getsize('stary')

0L

>>> for x in listdir('.'):

     print x, path.getsize(x)

    

tcl84.lib 190886

tclstub84.lib 2272

tix8184.lib 49054

tk84.lib 165420

tkstub84.lib 2996

tk8.4 0

tix8.1 0

tcl8.4 0

reg1.1 0

dde1.2 0

stary 0

plik 100

 

Funkcja path.getctime zwraca czas stworzenia, a path.getmtime czas ostatniej modyfikacji obiektu dyskowego:

 

>>> from time import ctime

>>> ctime(path.getctime('plik'))

'Thu Oct 12 12:26:50 2006'

>>> ctime(path.getmtime('plik'))

'Thu Oct 12 12:33:16 2006'

 

Funkcja walk(katalog nadrzędny, kolejność) służy do rekursywnego przechodzenia podanego katalogu wraz ze wszystkimi jego podkatalogami. Dla każdego znalezionego katalogu (łącznie z nadrzędnym) zwraca trójkę: (ścieżka, podkatalogi, pliki), gdzie ścieżka oznacza ścieżkę dostępu do katalogu, podkatalogi – listę nazw zawartych w nim podkatalogów, pliki – listę nazw zawartych w nim plików. Parametr kolejność (domyślnie True) ustawiony na False zwraca katalogi w odwrotnym porządku (zaczyna od najgłębiej położonego; może być to przydatne, jeżeli zamierzamy np. kasować podkatalogi).

 

>>> for sciezka, podkatalogi, pliki in walk(r'C:\Python24\Tcl'):

     print 'W katalogu %s znajduje się %i bajtów w %i plikach' \

% (sciezka, sum(path.getsize(path.join(sciezka, nazwa)) \

for nazwa in pliki), len(pliki))

 

W katalogu C:\Python24\Tcl znajduje się 410728 bajtów w 6 plikach

W katalogu C:\Python24\Tcl\tk8.4 znajduje się 436678 bajtów w 30 plikach

W katalogu C:\Python24\Tcl\tk8.4\msgs znajduje się 51740 bajtów w 12 plikach

W katalogu C:\Python24\Tcl\tk8.4\images znajduje się 97217 bajtów w 13 plikach

W katalogu C:\Python24\Tcl\tk8.4\demos znajduje się 269352 bajtów w 54 plikach

W katalogu C:\Python24\Tcl\tk8.4\demos\images znajduje się 277824 bajtów w 11 plikach

W katalogu C:\Python24\Tcl\tix8.1 znajduje się 596476 bajtów w 77 plikach

W katalogu C:\Python24\Tcl\tix8.1\pref znajduje się 236295 bajtów w 36 plikach

W katalogu C:\Python24\Tcl\tix8.1\bitmaps znajduje się 18805 bajtów w 58 plikach

W katalogu C:\Python24\Tcl\tcl8.4 znajduje się 121278 bajtów w 9 plikach

W katalogu C:\Python24\Tcl\tcl8.4\tcltest2.2 znajduje się 98660 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\tcl8.4\opt0.4 znajduje się 33631 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\tcl8.4\msgcat1.3 znajduje się 13083 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\tcl8.4\http2.4 znajduje się 24706 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\tcl8.4\http1.0 znajduje się 10494 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\tcl8.4\encoding znajduje się 1413736 bajtów w 78 plikach

W katalogu C:\Python24\Tcl\reg1.1 znajduje się 13182 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\dde1.2 znajduje się 13646 bajtów w 2 plikach

W katalogu C:\Python24\Tcl\stary znajduje się 0 bajtów w 0 plikach

 

Funkcja remove usuwa z dysku plik, a rmdir katalog o podanej nazwie:

 

>>> remove('plik')

>>> path.exists('plik')

False

>>> rmdir('stary')

>>> path.exists('stary')

False

 

Ćwiczenie 1. Napisz program, który znajdzie w podanym przez użytkownika katalogu i wszystkich jego podkatalogach wszystkie pliki, które zawierają podany przez użytkownika napis.

Ćwiczenie 2. Napisz program, który znajdzie w podanym przez użytkownika katalogu i wszystkich jego podkatalogach najstarszy i najdłuższy plik.

Ćwiczenie 3. Napisz program, który znajdzie w podanym przez użytkownika katalogu i wszystkich jego podkatalogach wszystkie zdublowane pliki, czyli takie pliki, których nazwa występuje jednocześnie w więcej niż jednym miejscu.