Python中的文件和目錄操作實(shí)現(xiàn)代碼
更新時(shí)間:2011年03月13日 13:03:15 作者:
對(duì)于文件和目錄的處理,雖然可以通過(guò)操作系統(tǒng)命令來(lái)完成,但是Python語(yǔ)言為了便于開(kāi)發(fā)人員以編程的方式處理相關(guān)工作,提供了許多處理文件和目錄的內(nèi)置函數(shù)。重要的是,這些函數(shù)無(wú)論是在Unix、Windows還是Macintosh平臺(tái)上,它們的使用方式是完全一致的。
本文將詳細(xì)解釋這些函數(shù)的使用方法。首先,我們介紹Python語(yǔ)言中類(lèi)似于Windows系統(tǒng)的dir命令的列出文件功能,然后描述如何測(cè)試一個(gè)文件名對(duì)應(yīng)的是一個(gè)標(biāo)準(zhǔn)文件、目錄還是鏈接,以及提取文件大小和日期的方法。之后,我們還將介紹如何刪除文件和目錄,如何復(fù)制和刪除文件,以及怎樣將一個(gè)完整的文件路徑分解成目錄部分和文件名部分,最后,我們講解目錄的創(chuàng)建,以及如何在目錄樹(shù)中移動(dòng)目錄并處理文件。
一、顯示目錄內(nèi)容
當(dāng)我們想要列出當(dāng)前目錄中所有擴(kuò)展名為.jpg或.gif的文件的時(shí)候,就可以使用glob模塊來(lái)完成此項(xiàng)任務(wù),如下所示:
import glob
filelist = glob.glob('*.jpg') + glob.glob('*.gif')
上述代碼使用了glob函數(shù),該函數(shù)的參數(shù)為要顯示的文件類(lèi)型。在這里,文件類(lèi)型是通過(guò)類(lèi)似UNIX操作系統(tǒng)shell風(fēng)格通配符描述的一些文件名來(lái)指定的。這些通配符的使用方法,具體請(qǐng)參考fnmatch模塊的文檔,那里有具體的說(shuō)明和示例。
為了顯示一個(gè)目錄中的全部文件,可以使用如下所示的os.listdir函數(shù):
files = os.listdir(r'C:\hpl\scripting\src\py\intro') #適用于 Windows
files = os.listdir('/home/hpl/scripting/src/py/intro') # 適用于Unix
# 跨平臺(tái)版本:
files = os.listdir(os.path.join(os.environ['scripting'],
'src', 'py', 'intro'))
files = os.listdir(os.curdir) # 當(dāng)前目錄中的所有文件
files = glob.glob('*') + glob.glob('.*')
二、測(cè)試文件類(lèi)型
我們知道,文件名、目錄名和鏈接名都是用一個(gè)字符串作為其標(biāo)識(shí)符的,但是給我們一個(gè)標(biāo)識(shí)符,我們?cè)撊绾未_定它所指的到底是常規(guī)文件文件名、目錄名還是鏈接名呢?這時(shí),我們可以使用os.path模塊提供的isfile函數(shù)、isdir函數(shù)和islink函數(shù)來(lái)達(dá)成我們的目標(biāo),如下所示:
print myfile, '是一個(gè)',
if os.path.isfile(myfile):
print 'plain file'
if os.path.isdir(myfile):
print 'directory'
if os.path.islink(myfile):
print 'link'
您還可以查找文件的日期及其大?。?
time_of_last_access = os.path.getatime(myfile)
time_of_last_modification = os.path.getmtime(myfile)
size = os.path.getsize(myfile)
這里的時(shí)間以秒為單位,并且從1970年1月1日開(kāi)始算起。為了獲取以天為單位的最后訪問(wèn)日期,可以使用下列代碼:
import time # time.time()返回當(dāng)前時(shí)間
age_in_days = (time.time()-time_of_last_access)/(60*60*24)
為了獲取文件的詳細(xì)信息,可以使用os.stat函數(shù)和stat模塊中的其它實(shí)用程序來(lái)達(dá)到目的,如下:
import stat
myfile_stat = os.stat(myfile)
size = myfile_stat[stat.ST_SIZE]
mode = myfile_stat[stat.ST_MODE]
if stat.S_ISREG(mode):
print '%(myfile)是一個(gè)常規(guī)文件,大小為 %(size)d 字節(jié)' %\
vars()
有關(guān)stat模塊的詳細(xì)信息,請(qǐng)參見(jiàn)Python Library Reference。若想測(cè)試一個(gè)文件的讀、寫(xiě)以及執(zhí)行權(quán)限,可以用os.access函數(shù),具體如下所示:
if os.access(myfile, os.W_OK):
print myfile, '具有寫(xiě)權(quán)限'
if os.access(myfile, os.R_OK | os.W_OK | os.X_OK):
print myfile, '具有讀、寫(xiě)以及執(zhí)行權(quán)限'
像上面這樣的測(cè)試代碼,對(duì)CGI腳本來(lái)說(shuō)非常有用。
三、文件和目錄的刪除
若要?jiǎng)h除單個(gè)文件的話,可以使用os.remove函數(shù),例如:os.remove('mydata.dat')。Os.remove的別名是os.unlink,不過(guò)后者跟傳統(tǒng)的UNIX操作系統(tǒng)以及Perl中清除文件的函數(shù)重名。我們可以使用下列方式來(lái)刪除一組文件,如所有以.jpg以及*.gif為擴(kuò)展名的文件:
for file in glob.glob('*.jpg') + glob.glob('*.gif'):
os.remove(file)
大家知道,只有當(dāng)目錄中內(nèi)容已經(jīng)被清空的時(shí)候,我們才可以使用rmdir命令來(lái)刪除該目錄。不過(guò),我們經(jīng)常想要?jiǎng)h除一個(gè)含有許多文件的目錄樹(shù),這時(shí)我們可以使用shutil模塊提供的rmtree函數(shù),如下所示:
shutil.rmtree('mydir')
它相當(dāng)于UNIX操作系統(tǒng)中的命令rm -rf mydir。
我們可以建立一個(gè)自定義函數(shù),使其在進(jìn)行刪除操作的時(shí)候?qū)⑽募湍夸涀鐾葘?duì)待,其典型用法如下所示:
remove('my.dat') #刪除當(dāng)個(gè)文件my.dat
remove('mytree') #刪除單個(gè)目錄樹(shù) mytree
# 通過(guò)字符串列表中的名稱(chēng)來(lái)刪除多個(gè)文件/目錄樹(shù):
remove(glob.glob('*.tmp') + glob.glob('*.temp'))
remove(['my.dat','mydir','yourdir'] + glob.glob('*.data'))
下面是remove函數(shù)的實(shí)現(xiàn):
def remove(files):
"""刪除一個(gè)或多個(gè)文件和/或目錄。"""
if isinstance(files, str): # files是個(gè)字符串嗎?
files = [files] # 把files從字符串轉(zhuǎn)為列表
if not isinstance(files, list): # files不是列表嗎?
for file in files:
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file):
os.remove(file)
下面測(cè)試一下remove函數(shù)的靈活性:
# 建立10個(gè)目錄tmp_* ,以及10各文件tmp__*:
for i in range(10):
os.mkdir('tmp_'+str(i))
f = open('tmp__'+str(i), 'w'); f.close()
remove('tmp_1') # tmp_1為目錄
remove(glob.glob('tmp_[0-9]') + glob.glob('tmp__[0-9]'))
作為上述remove函數(shù)實(shí)現(xiàn)的一個(gè)注記,我們進(jìn)行了下列測(cè)試:
if not isinstance(files, list):
它實(shí)際上是過(guò)于嚴(yán)厲。我們需要的只是一個(gè)被遍歷的一個(gè)文件/目錄名序列。實(shí)際上,我們并不關(guān)心名稱(chēng)是否存儲(chǔ)在一個(gè)列表、元組或者數(shù)值數(shù)組中,所以更好的測(cè)試應(yīng)該像下面這樣:
if not operator.isSequenceType(files):
四、文件的復(fù)制與重命名
當(dāng)我們要復(fù)制文件的時(shí)候,可以使用shutil模塊:
import shutil
shutil.copy(myfile, tmpfile)
#拷貝最后訪問(wèn)時(shí)間和最后修改時(shí)間:
shutil.copy2(myfile, tmpfile)
# 拷貝一個(gè)目錄樹(shù):
shutil.copytree(root_of_tree, destination_dir, True)
Copytree的第三個(gè)參數(shù)規(guī)定對(duì)符號(hào)鏈接的處理,其中True表示保留符號(hào)鏈接;而False則意味著使用文件的物理副本替代符號(hào)鏈接。
Python語(yǔ)言能夠很好地支持路徑名的跨平臺(tái)組成:Os.path.join能使用正確的分界符(在UNIX和Mac OS X操作系統(tǒng)中使用/,在 Windows 上使用\)來(lái)聯(lián)接目錄和文件名,變量os.curdir和os.pardir分別表示當(dāng)前工作目錄及其父目錄。 像下面的UNIX操作系統(tǒng)命令
cp http://www.dbjr.com.cn/f1.c .
可以使用Python語(yǔ)言提供一個(gè)跨平臺(tái)的實(shí)現(xiàn):
shutil.copy(os.path.join(os.pardir,os.pardir,'f1.c'), os.curdir)
Os模塊中的rename函數(shù)通常被用于重命名一個(gè)文件:
os.rename(myfile, 'tmp.1') # 將myfile重命名為'tmp.1'
這個(gè)函數(shù)也可用來(lái)在相同的文件系統(tǒng)之內(nèi)移動(dòng)文件。這里,我們將myfile移動(dòng)到目錄d下面:
os.rename(myfile, os.path.join(d, myfile))
在跨文件系統(tǒng)移動(dòng)文件的時(shí)候,可以先使用shutil.copy2來(lái)復(fù)制文件,然后再刪除原來(lái)的副本即可,如下:
shutil.copy2(myfile, os.path.join(d, myfile))
os.remove(myfile)
后面這種移動(dòng)文件的方法是最安全的。
五、分解路徑名
假設(shè)我們使用變量fname來(lái)存放一個(gè)包含完整路徑的文件名,例如:
/usr/home/hpl/scripting/python/intro/hw.py
有時(shí)候,我們需要將這樣的文件路徑拆分為基本名稱(chēng)hw.py和目錄名/usr/home/hpl/scripting/python/intro。在Python語(yǔ)言中,可以使用下列代碼達(dá)到目的:
basename = os.path.basename(fname)
dirname = os.path.dirname(fname)
# 或
dirname, basename = os.path.split(fname)
擴(kuò)展名是通過(guò)os.path.splitext函數(shù)提取出來(lái)的,
root, extension = os.path.splitext(fname)
這樣,fname中的擴(kuò)展名部分即.py被賦給變量extension,而其余部分則賦給了變量root。如果想得到不帶點(diǎn)號(hào)的擴(kuò)展名的話,只需使用os.path.splitext(fname)[1][1:]即可。
假設(shè)一個(gè)文件名為f,其擴(kuò)展名隨意,若想將其擴(kuò)展名改為ext,可以使用下面的代碼:
newfile = os.path.splitext(f)[0] + ext
下面是一個(gè)具體的示例:
>>> f = '/some/path/case2.data_source'
>>> moviefile = os.path.basename(os.path.splitext(f)[0] + '.mpg')
>>> moviefile
'case2.mpg'
六、目錄的創(chuàng)建和移動(dòng)
Os模塊中的函數(shù)mkdir可以用來(lái)創(chuàng)建目錄,而chdir函數(shù)則可以移動(dòng)目錄,如下:
origdir = os.getcwd() # 將當(dāng)前位置記下來(lái)
newdir = os.path.join(os.pardir, 'mynewdir')
if not os.path.isdir(newdir):
os.mkdir(newdir) # 或者os.mkdir(newdir,'0755')
os.chdir(newdir)
...
os.chdir(origdir) # 返回原目錄
os.chdir(os.environ['HOME']) # 移到主目錄
假設(shè)我們想要在自己的主目錄下創(chuàng)建一個(gè)新目錄py/src/test1,但是目前py、src和test1都不存在。如果使用mkdir命令來(lái)創(chuàng)建的話,需要使用三次才能建好這個(gè)嵌套的目錄,但是使用Python語(yǔ)言提供的os.makedirs命令的話,則無(wú)需這樣麻煩了,該命令可以一次建好整個(gè)目錄:
os.makedirs(os.path.join(os.environ['HOME'],'py','src','test1'))
七、遍歷目錄樹(shù)
下面的函數(shù)調(diào)用
os.path.walk(root, myfunc, arg)
將遍歷root目錄樹(shù);然后,對(duì)每個(gè)目錄名dirname分別調(diào)用myfunc(arg, dirname, files)即可,這里參數(shù)files是dir中的文件名列表(可通過(guò)調(diào)用os.listdir(dirname)來(lái)獲得);arg是用戶(hù)從調(diào)用代碼中傳遞來(lái)的參數(shù)。對(duì)于UNIX操作系統(tǒng)用戶(hù)來(lái)說(shuō),Python語(yǔ)言中跨平臺(tái)的os.path.walk相當(dāng)于Unix命令find。
在解釋os.path.walk的用法的時(shí)候,人們常使用寫(xiě)出主目錄中所有子目錄內(nèi)的文件的名稱(chēng)為例進(jìn)行說(shuō)明。當(dāng)然,我們也可以在一個(gè)交互式的Python命令行中使用下列代碼段來(lái)體會(huì)os.path.walk的使用:
def ls(arg, dirname, files):
print dirname, 'has the files', files
os.path.walk(os.environ['HOME'], ls, None)
本例中,參數(shù)arg并非必需,所以在os.path.walk調(diào)用中讓其取值為None即可。
為了列出主目錄中所有大于1Mb的文件,可以使用下面的代碼:
def checksize1(arg, dirname, files):
for file in files:
filepath = os.path.join(dirname, file)
if os.path.isfile(filepath):
size = os.path.getsize(filepath)
if size > 1000000:
size_in_Mb = size/1000000.0
arg.append((size_in_Mb, filename))
bigfiles = []
root = os.environ['HOME']
os.path.walk(root, checksize1, bigfiles)
for size, name in bigfiles:
print name, '大小為', size, 'Mb'
現(xiàn)在,我們使用arg來(lái)建立一個(gè)數(shù)據(jù)結(jié)構(gòu),這里是一個(gè)2元組構(gòu)成的列表,其中每個(gè)2元組存放文件的尺寸(以MB為單位)和完整的文件路徑。如果用于所有目錄的函數(shù)調(diào)用中都要更改arg的話,那么arg必須是一個(gè)可變的數(shù)據(jù)結(jié)構(gòu),即允許適當(dāng)?shù)剡M(jìn)行修改。
參數(shù)dirname是當(dāng)前正在訪問(wèn)的目錄的絕對(duì)路徑,而參數(shù)files內(nèi)的文件名則是相對(duì)于dirname的相對(duì)路徑。在此期間,當(dāng)前工作目錄并沒(méi)有改變,那就是說(shuō)該腳本仍然呆在腳本啟動(dòng)時(shí)刻所在的目錄中。這就是為什么我們需要把filepath弄成帶有dirname和file的絕對(duì)路徑的原因。若要改變當(dāng)前工作目錄為dirname,只要在針對(duì)每個(gè)目錄調(diào)用os.path.walk的函數(shù)中調(diào)用一下os.chdir(dirname),然后在該函數(shù)的末尾重新調(diào)用os.chdir(dirname)將當(dāng)前工作目錄改回原值即可,如下所示:
def somefunc(arg, dirname, files):
origdir = os.getcwd(); os.chdir(dirname)
os.chdir(origdir)
os.path.walk(root, somefunc, arg)
當(dāng)然,如果您愿意也可以編寫(xiě)具有類(lèi)似功能的代碼來(lái)替代os.path.walk。下面的代碼,將針對(duì)每個(gè)文件而非每個(gè)目錄來(lái)調(diào)用的自定義函數(shù),如下所示:
def find(func, rootdir, arg=None):
# 對(duì)rootdir目錄中的每個(gè)文件調(diào)用func
files = os.listdir(rootdir) # 獲取rootdir目錄中的所有文件
files.sort(lambda a, b: cmp(a.lower(), b.lower()))
for file in files:
fullpath = os.path.join(rootdir, file)
if os.path.islink(fullpath):
pass
elif os.path.isdir(fullpath):
find(func, fullpath, arg)
elif os.path.isfile(fullpath):
func(fullpath, arg)
else:
print 'find: cannot treat ', fullpath
上面的函數(shù)find可以從scitools模塊中獲取。與內(nèi)置函數(shù)os.path.walk相反,我們的find函數(shù)以大小寫(xiě)敏感的字母順序來(lái)訪問(wèn)文件和目錄。
我們可以使用find函數(shù)來(lái)列出所有大于1Mb的文件:
def checksize2(fullpath, bigfiles):
size = os.path.getsize(fullpath)
if size > 1000000:
bigfiles.append('%.2fMb %s' % (size/1000000.0, fullpath))
bigfiles = []
root = os.environ['HOME']
find(checksize2, root, bigfiles)
for fileinfo in bigfiles:
print fileinfo
參數(shù)arg帶來(lái)了巨大的靈活性。我們可以使用它來(lái)同時(shí)存放輸入數(shù)據(jù)和生成的數(shù)據(jù)結(jié)構(gòu)。下一個(gè)范例將收集所有大于一定尺寸的帶有規(guī)定擴(kuò)展名的文件的文件名和大小。輸出的結(jié)果按照文件大小排列。
bigfiles = {'filelist': [], # 文件名和大小列表
'extensions': ('.*ps', '.tiff', '.bmp'),
'size_limit': 1000000, # 1 Mb
}
find(checksize3, os.environ['HOME'], bigfiles)
def checksize3(fullpath, arg):
treat_file = False
ext = os.path.splitext(fullpath)[1]
import fnmatch # Unix的shell風(fēng)格的通配符匹配
for s in arg['extensions']:
if fnmatch.fnmatch(ext, s):
treat_file = True # fullpath帶有正確的擴(kuò)展名
size = os.path.getsize(fullpath)
if treat_file and size > arg['size_limit']:
size = '%.2fMb' % (size/1000000.0) # 打印
arg['filelist'].append({'size': size, 'name': fullpath})
# 按照大小排列文件
def filesort(a, b):
return cmp(float(a['size'][:-2]), float(b['size'][:-2]))
bigfiles['filelist'].sort(filesort)
bigfiles['filelist'].reverse()
for fileinfo in bigfiles['filelist']:
print fileinfo['name'], fileinfo['size']
注意為列表排序的函數(shù),bigfiles['filelist']函數(shù)中的每個(gè)元素就是一個(gè)字典,鍵size保存著一個(gè)字符串,不過(guò)在進(jìn)行比較之前我們必須將單位Mb(最后兩個(gè)字符)去掉,并將其轉(zhuǎn)換為浮點(diǎn)數(shù)。
八、小結(jié)
對(duì)于文件和目錄的處理,雖然可以通過(guò)操作系統(tǒng)命令來(lái)完成,但是Python語(yǔ)言為了便于開(kāi)發(fā)人員以編程的方式處理相關(guān)工作,提供了許多處理文件和目錄的內(nèi)置函數(shù)。重要的是,這些函數(shù)無(wú)論是在Unix、Windows還是Macintosh平臺(tái)上,它們的使用方式是完全一致的。本文詳細(xì)解釋了這些函數(shù)的使用方法,其中,我們首先介紹了顯示目錄內(nèi)容的功能,然后描述如何測(cè)試一個(gè)文件名對(duì)應(yīng)的是一個(gè)標(biāo)準(zhǔn)文件、目錄還是鏈接,以及提取文件大小和日期的方法。之后,我們還將介紹如何刪除文件和目錄,如何復(fù)制和刪除文件,以及怎樣將一個(gè)完整的文件路徑分解成目錄部分和文件名部分,最后,我們講解目錄的創(chuàng)建,以及如何在目錄樹(shù)中移動(dòng)目錄并處理文件。
一、顯示目錄內(nèi)容
當(dāng)我們想要列出當(dāng)前目錄中所有擴(kuò)展名為.jpg或.gif的文件的時(shí)候,就可以使用glob模塊來(lái)完成此項(xiàng)任務(wù),如下所示:
import glob
filelist = glob.glob('*.jpg') + glob.glob('*.gif')
上述代碼使用了glob函數(shù),該函數(shù)的參數(shù)為要顯示的文件類(lèi)型。在這里,文件類(lèi)型是通過(guò)類(lèi)似UNIX操作系統(tǒng)shell風(fēng)格通配符描述的一些文件名來(lái)指定的。這些通配符的使用方法,具體請(qǐng)參考fnmatch模塊的文檔,那里有具體的說(shuō)明和示例。
為了顯示一個(gè)目錄中的全部文件,可以使用如下所示的os.listdir函數(shù):
復(fù)制代碼 代碼如下:
files = os.listdir(r'C:\hpl\scripting\src\py\intro') #適用于 Windows
files = os.listdir('/home/hpl/scripting/src/py/intro') # 適用于Unix
# 跨平臺(tái)版本:
files = os.listdir(os.path.join(os.environ['scripting'],
'src', 'py', 'intro'))
files = os.listdir(os.curdir) # 當(dāng)前目錄中的所有文件
files = glob.glob('*') + glob.glob('.*')
二、測(cè)試文件類(lèi)型
我們知道,文件名、目錄名和鏈接名都是用一個(gè)字符串作為其標(biāo)識(shí)符的,但是給我們一個(gè)標(biāo)識(shí)符,我們?cè)撊绾未_定它所指的到底是常規(guī)文件文件名、目錄名還是鏈接名呢?這時(shí),我們可以使用os.path模塊提供的isfile函數(shù)、isdir函數(shù)和islink函數(shù)來(lái)達(dá)成我們的目標(biāo),如下所示:
復(fù)制代碼 代碼如下:
print myfile, '是一個(gè)',
if os.path.isfile(myfile):
print 'plain file'
if os.path.isdir(myfile):
print 'directory'
if os.path.islink(myfile):
print 'link'
您還可以查找文件的日期及其大?。?
復(fù)制代碼 代碼如下:
time_of_last_access = os.path.getatime(myfile)
time_of_last_modification = os.path.getmtime(myfile)
size = os.path.getsize(myfile)
這里的時(shí)間以秒為單位,并且從1970年1月1日開(kāi)始算起。為了獲取以天為單位的最后訪問(wèn)日期,可以使用下列代碼:
import time # time.time()返回當(dāng)前時(shí)間
age_in_days = (time.time()-time_of_last_access)/(60*60*24)
為了獲取文件的詳細(xì)信息,可以使用os.stat函數(shù)和stat模塊中的其它實(shí)用程序來(lái)達(dá)到目的,如下:
復(fù)制代碼 代碼如下:
import stat
myfile_stat = os.stat(myfile)
size = myfile_stat[stat.ST_SIZE]
mode = myfile_stat[stat.ST_MODE]
if stat.S_ISREG(mode):
print '%(myfile)是一個(gè)常規(guī)文件,大小為 %(size)d 字節(jié)' %\
vars()
有關(guān)stat模塊的詳細(xì)信息,請(qǐng)參見(jiàn)Python Library Reference。若想測(cè)試一個(gè)文件的讀、寫(xiě)以及執(zhí)行權(quán)限,可以用os.access函數(shù),具體如下所示:
if os.access(myfile, os.W_OK):
print myfile, '具有寫(xiě)權(quán)限'
if os.access(myfile, os.R_OK | os.W_OK | os.X_OK):
print myfile, '具有讀、寫(xiě)以及執(zhí)行權(quán)限'
像上面這樣的測(cè)試代碼,對(duì)CGI腳本來(lái)說(shuō)非常有用。
三、文件和目錄的刪除
若要?jiǎng)h除單個(gè)文件的話,可以使用os.remove函數(shù),例如:os.remove('mydata.dat')。Os.remove的別名是os.unlink,不過(guò)后者跟傳統(tǒng)的UNIX操作系統(tǒng)以及Perl中清除文件的函數(shù)重名。我們可以使用下列方式來(lái)刪除一組文件,如所有以.jpg以及*.gif為擴(kuò)展名的文件:
for file in glob.glob('*.jpg') + glob.glob('*.gif'):
os.remove(file)
大家知道,只有當(dāng)目錄中內(nèi)容已經(jīng)被清空的時(shí)候,我們才可以使用rmdir命令來(lái)刪除該目錄。不過(guò),我們經(jīng)常想要?jiǎng)h除一個(gè)含有許多文件的目錄樹(shù),這時(shí)我們可以使用shutil模塊提供的rmtree函數(shù),如下所示:
shutil.rmtree('mydir')
它相當(dāng)于UNIX操作系統(tǒng)中的命令rm -rf mydir。
我們可以建立一個(gè)自定義函數(shù),使其在進(jìn)行刪除操作的時(shí)候?qū)⑽募湍夸涀鐾葘?duì)待,其典型用法如下所示:
remove('my.dat') #刪除當(dāng)個(gè)文件my.dat
remove('mytree') #刪除單個(gè)目錄樹(shù) mytree
# 通過(guò)字符串列表中的名稱(chēng)來(lái)刪除多個(gè)文件/目錄樹(shù):
remove(glob.glob('*.tmp') + glob.glob('*.temp'))
remove(['my.dat','mydir','yourdir'] + glob.glob('*.data'))
下面是remove函數(shù)的實(shí)現(xiàn):
def remove(files):
"""刪除一個(gè)或多個(gè)文件和/或目錄。"""
if isinstance(files, str): # files是個(gè)字符串嗎?
files = [files] # 把files從字符串轉(zhuǎn)為列表
if not isinstance(files, list): # files不是列表嗎?
for file in files:
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file):
os.remove(file)
下面測(cè)試一下remove函數(shù)的靈活性:
復(fù)制代碼 代碼如下:
# 建立10個(gè)目錄tmp_* ,以及10各文件tmp__*:
for i in range(10):
os.mkdir('tmp_'+str(i))
f = open('tmp__'+str(i), 'w'); f.close()
remove('tmp_1') # tmp_1為目錄
remove(glob.glob('tmp_[0-9]') + glob.glob('tmp__[0-9]'))
作為上述remove函數(shù)實(shí)現(xiàn)的一個(gè)注記,我們進(jìn)行了下列測(cè)試:
if not isinstance(files, list):
它實(shí)際上是過(guò)于嚴(yán)厲。我們需要的只是一個(gè)被遍歷的一個(gè)文件/目錄名序列。實(shí)際上,我們并不關(guān)心名稱(chēng)是否存儲(chǔ)在一個(gè)列表、元組或者數(shù)值數(shù)組中,所以更好的測(cè)試應(yīng)該像下面這樣:
if not operator.isSequenceType(files):
四、文件的復(fù)制與重命名
當(dāng)我們要復(fù)制文件的時(shí)候,可以使用shutil模塊:
import shutil
shutil.copy(myfile, tmpfile)
#拷貝最后訪問(wèn)時(shí)間和最后修改時(shí)間:
shutil.copy2(myfile, tmpfile)
# 拷貝一個(gè)目錄樹(shù):
shutil.copytree(root_of_tree, destination_dir, True)
Copytree的第三個(gè)參數(shù)規(guī)定對(duì)符號(hào)鏈接的處理,其中True表示保留符號(hào)鏈接;而False則意味著使用文件的物理副本替代符號(hào)鏈接。
Python語(yǔ)言能夠很好地支持路徑名的跨平臺(tái)組成:Os.path.join能使用正確的分界符(在UNIX和Mac OS X操作系統(tǒng)中使用/,在 Windows 上使用\)來(lái)聯(lián)接目錄和文件名,變量os.curdir和os.pardir分別表示當(dāng)前工作目錄及其父目錄。 像下面的UNIX操作系統(tǒng)命令
cp http://www.dbjr.com.cn/f1.c .
可以使用Python語(yǔ)言提供一個(gè)跨平臺(tái)的實(shí)現(xiàn):
shutil.copy(os.path.join(os.pardir,os.pardir,'f1.c'), os.curdir)
Os模塊中的rename函數(shù)通常被用于重命名一個(gè)文件:
os.rename(myfile, 'tmp.1') # 將myfile重命名為'tmp.1'
這個(gè)函數(shù)也可用來(lái)在相同的文件系統(tǒng)之內(nèi)移動(dòng)文件。這里,我們將myfile移動(dòng)到目錄d下面:
os.rename(myfile, os.path.join(d, myfile))
在跨文件系統(tǒng)移動(dòng)文件的時(shí)候,可以先使用shutil.copy2來(lái)復(fù)制文件,然后再刪除原來(lái)的副本即可,如下:
shutil.copy2(myfile, os.path.join(d, myfile))
os.remove(myfile)
后面這種移動(dòng)文件的方法是最安全的。
五、分解路徑名
假設(shè)我們使用變量fname來(lái)存放一個(gè)包含完整路徑的文件名,例如:
/usr/home/hpl/scripting/python/intro/hw.py
有時(shí)候,我們需要將這樣的文件路徑拆分為基本名稱(chēng)hw.py和目錄名/usr/home/hpl/scripting/python/intro。在Python語(yǔ)言中,可以使用下列代碼達(dá)到目的:
basename = os.path.basename(fname)
dirname = os.path.dirname(fname)
# 或
dirname, basename = os.path.split(fname)
擴(kuò)展名是通過(guò)os.path.splitext函數(shù)提取出來(lái)的,
root, extension = os.path.splitext(fname)
這樣,fname中的擴(kuò)展名部分即.py被賦給變量extension,而其余部分則賦給了變量root。如果想得到不帶點(diǎn)號(hào)的擴(kuò)展名的話,只需使用os.path.splitext(fname)[1][1:]即可。
假設(shè)一個(gè)文件名為f,其擴(kuò)展名隨意,若想將其擴(kuò)展名改為ext,可以使用下面的代碼:
newfile = os.path.splitext(f)[0] + ext
下面是一個(gè)具體的示例:
>>> f = '/some/path/case2.data_source'
>>> moviefile = os.path.basename(os.path.splitext(f)[0] + '.mpg')
>>> moviefile
'case2.mpg'
六、目錄的創(chuàng)建和移動(dòng)
Os模塊中的函數(shù)mkdir可以用來(lái)創(chuàng)建目錄,而chdir函數(shù)則可以移動(dòng)目錄,如下:
origdir = os.getcwd() # 將當(dāng)前位置記下來(lái)
newdir = os.path.join(os.pardir, 'mynewdir')
if not os.path.isdir(newdir):
os.mkdir(newdir) # 或者os.mkdir(newdir,'0755')
os.chdir(newdir)
...
os.chdir(origdir) # 返回原目錄
os.chdir(os.environ['HOME']) # 移到主目錄
假設(shè)我們想要在自己的主目錄下創(chuàng)建一個(gè)新目錄py/src/test1,但是目前py、src和test1都不存在。如果使用mkdir命令來(lái)創(chuàng)建的話,需要使用三次才能建好這個(gè)嵌套的目錄,但是使用Python語(yǔ)言提供的os.makedirs命令的話,則無(wú)需這樣麻煩了,該命令可以一次建好整個(gè)目錄:
os.makedirs(os.path.join(os.environ['HOME'],'py','src','test1'))
七、遍歷目錄樹(shù)
下面的函數(shù)調(diào)用
os.path.walk(root, myfunc, arg)
將遍歷root目錄樹(shù);然后,對(duì)每個(gè)目錄名dirname分別調(diào)用myfunc(arg, dirname, files)即可,這里參數(shù)files是dir中的文件名列表(可通過(guò)調(diào)用os.listdir(dirname)來(lái)獲得);arg是用戶(hù)從調(diào)用代碼中傳遞來(lái)的參數(shù)。對(duì)于UNIX操作系統(tǒng)用戶(hù)來(lái)說(shuō),Python語(yǔ)言中跨平臺(tái)的os.path.walk相當(dāng)于Unix命令find。
在解釋os.path.walk的用法的時(shí)候,人們常使用寫(xiě)出主目錄中所有子目錄內(nèi)的文件的名稱(chēng)為例進(jìn)行說(shuō)明。當(dāng)然,我們也可以在一個(gè)交互式的Python命令行中使用下列代碼段來(lái)體會(huì)os.path.walk的使用:
def ls(arg, dirname, files):
print dirname, 'has the files', files
os.path.walk(os.environ['HOME'], ls, None)
本例中,參數(shù)arg并非必需,所以在os.path.walk調(diào)用中讓其取值為None即可。
為了列出主目錄中所有大于1Mb的文件,可以使用下面的代碼:
def checksize1(arg, dirname, files):
for file in files:
filepath = os.path.join(dirname, file)
if os.path.isfile(filepath):
size = os.path.getsize(filepath)
if size > 1000000:
size_in_Mb = size/1000000.0
arg.append((size_in_Mb, filename))
bigfiles = []
root = os.environ['HOME']
os.path.walk(root, checksize1, bigfiles)
for size, name in bigfiles:
print name, '大小為', size, 'Mb'
現(xiàn)在,我們使用arg來(lái)建立一個(gè)數(shù)據(jù)結(jié)構(gòu),這里是一個(gè)2元組構(gòu)成的列表,其中每個(gè)2元組存放文件的尺寸(以MB為單位)和完整的文件路徑。如果用于所有目錄的函數(shù)調(diào)用中都要更改arg的話,那么arg必須是一個(gè)可變的數(shù)據(jù)結(jié)構(gòu),即允許適當(dāng)?shù)剡M(jìn)行修改。
參數(shù)dirname是當(dāng)前正在訪問(wèn)的目錄的絕對(duì)路徑,而參數(shù)files內(nèi)的文件名則是相對(duì)于dirname的相對(duì)路徑。在此期間,當(dāng)前工作目錄并沒(méi)有改變,那就是說(shuō)該腳本仍然呆在腳本啟動(dòng)時(shí)刻所在的目錄中。這就是為什么我們需要把filepath弄成帶有dirname和file的絕對(duì)路徑的原因。若要改變當(dāng)前工作目錄為dirname,只要在針對(duì)每個(gè)目錄調(diào)用os.path.walk的函數(shù)中調(diào)用一下os.chdir(dirname),然后在該函數(shù)的末尾重新調(diào)用os.chdir(dirname)將當(dāng)前工作目錄改回原值即可,如下所示:
def somefunc(arg, dirname, files):
origdir = os.getcwd(); os.chdir(dirname)
os.chdir(origdir)
os.path.walk(root, somefunc, arg)
當(dāng)然,如果您愿意也可以編寫(xiě)具有類(lèi)似功能的代碼來(lái)替代os.path.walk。下面的代碼,將針對(duì)每個(gè)文件而非每個(gè)目錄來(lái)調(diào)用的自定義函數(shù),如下所示:
def find(func, rootdir, arg=None):
# 對(duì)rootdir目錄中的每個(gè)文件調(diào)用func
files = os.listdir(rootdir) # 獲取rootdir目錄中的所有文件
files.sort(lambda a, b: cmp(a.lower(), b.lower()))
for file in files:
fullpath = os.path.join(rootdir, file)
if os.path.islink(fullpath):
pass
elif os.path.isdir(fullpath):
find(func, fullpath, arg)
elif os.path.isfile(fullpath):
func(fullpath, arg)
else:
print 'find: cannot treat ', fullpath
上面的函數(shù)find可以從scitools模塊中獲取。與內(nèi)置函數(shù)os.path.walk相反,我們的find函數(shù)以大小寫(xiě)敏感的字母順序來(lái)訪問(wèn)文件和目錄。
我們可以使用find函數(shù)來(lái)列出所有大于1Mb的文件:
def checksize2(fullpath, bigfiles):
size = os.path.getsize(fullpath)
if size > 1000000:
bigfiles.append('%.2fMb %s' % (size/1000000.0, fullpath))
bigfiles = []
root = os.environ['HOME']
find(checksize2, root, bigfiles)
for fileinfo in bigfiles:
print fileinfo
參數(shù)arg帶來(lái)了巨大的靈活性。我們可以使用它來(lái)同時(shí)存放輸入數(shù)據(jù)和生成的數(shù)據(jù)結(jié)構(gòu)。下一個(gè)范例將收集所有大于一定尺寸的帶有規(guī)定擴(kuò)展名的文件的文件名和大小。輸出的結(jié)果按照文件大小排列。
bigfiles = {'filelist': [], # 文件名和大小列表
'extensions': ('.*ps', '.tiff', '.bmp'),
'size_limit': 1000000, # 1 Mb
}
find(checksize3, os.environ['HOME'], bigfiles)
def checksize3(fullpath, arg):
treat_file = False
ext = os.path.splitext(fullpath)[1]
import fnmatch # Unix的shell風(fēng)格的通配符匹配
for s in arg['extensions']:
if fnmatch.fnmatch(ext, s):
treat_file = True # fullpath帶有正確的擴(kuò)展名
size = os.path.getsize(fullpath)
if treat_file and size > arg['size_limit']:
size = '%.2fMb' % (size/1000000.0) # 打印
arg['filelist'].append({'size': size, 'name': fullpath})
# 按照大小排列文件
def filesort(a, b):
return cmp(float(a['size'][:-2]), float(b['size'][:-2]))
bigfiles['filelist'].sort(filesort)
bigfiles['filelist'].reverse()
for fileinfo in bigfiles['filelist']:
print fileinfo['name'], fileinfo['size']
注意為列表排序的函數(shù),bigfiles['filelist']函數(shù)中的每個(gè)元素就是一個(gè)字典,鍵size保存著一個(gè)字符串,不過(guò)在進(jìn)行比較之前我們必須將單位Mb(最后兩個(gè)字符)去掉,并將其轉(zhuǎn)換為浮點(diǎn)數(shù)。
八、小結(jié)
對(duì)于文件和目錄的處理,雖然可以通過(guò)操作系統(tǒng)命令來(lái)完成,但是Python語(yǔ)言為了便于開(kāi)發(fā)人員以編程的方式處理相關(guān)工作,提供了許多處理文件和目錄的內(nèi)置函數(shù)。重要的是,這些函數(shù)無(wú)論是在Unix、Windows還是Macintosh平臺(tái)上,它們的使用方式是完全一致的。本文詳細(xì)解釋了這些函數(shù)的使用方法,其中,我們首先介紹了顯示目錄內(nèi)容的功能,然后描述如何測(cè)試一個(gè)文件名對(duì)應(yīng)的是一個(gè)標(biāo)準(zhǔn)文件、目錄還是鏈接,以及提取文件大小和日期的方法。之后,我們還將介紹如何刪除文件和目錄,如何復(fù)制和刪除文件,以及怎樣將一個(gè)完整的文件路徑分解成目錄部分和文件名部分,最后,我們講解目錄的創(chuàng)建,以及如何在目錄樹(shù)中移動(dòng)目錄并處理文件。
相關(guān)文章
Tensorflow使用tfrecord輸入數(shù)據(jù)格式
這篇文章主要介紹了Tensorflow使用tfrecord輸入數(shù)據(jù)格式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Python如何設(shè)置指定窗口為前臺(tái)活動(dòng)窗口
這篇文章主要介紹了Python如何設(shè)置指定窗口為前臺(tái)活動(dòng)窗口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08numpy.bincount用于復(fù)數(shù)權(quán)重的方法
numpy.bincount是NumPy庫(kù)中的一個(gè)函數(shù),它用于計(jì)算整數(shù)數(shù)組中每個(gè)值的出現(xiàn)次數(shù),numpy.bincount函數(shù)在統(tǒng)計(jì)整數(shù)數(shù)組中每個(gè)值的出現(xiàn)次數(shù)或權(quán)重和時(shí)非常有用,本文給大家介紹numpy.bincount如何用于復(fù)數(shù)權(quán)重,感興趣的朋友跟隨小編一起看看吧2023-11-11Django+Uwsgi+Nginx如何實(shí)現(xiàn)生產(chǎn)環(huán)境部署
這篇文章主要介紹了Django+Uwsgi+Nginx如何實(shí)現(xiàn)生產(chǎn)環(huán)境部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07Python中property函數(shù)用法實(shí)例分析
這篇文章主要介紹了Python中property函數(shù)用法,結(jié)合實(shí)例形式分析了property函數(shù)的功能、參數(shù)、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-06-06