Python中的文件和目錄操作


 
  • Part 1
# os 模塊

os.sep 可以取代操作系統特定的路徑分隔符。windows下為 '\\'
os.name 字符串指示你正在使用的平台。比如對於Windows,它是'nt',而對於Linux/Unix用戶,它是 'posix'
os.getcwd() 函數得到當前工作目錄,即當前Python腳本工作的目錄路徑
os.getenv() 獲取一個環境變量,如果沒有返回none
os.putenv(key, value) 設置一個環境變量值
os.listdir(path) 返回指定目錄下的所有文件和目錄名
os.remove(path) 函數用來刪除一個文件
os.system(command) 函數用來運行shell命令
os.linesep 字符串給出當前平台使用的行終止符。例如,Windows使用 '\r\n',Linux使用 '\n' 而Mac使用 '\r'
os.path.split(path)  函數返回一個路徑的目錄名和文件名
os.path.isfile() 和os.path.isdir()函數分別檢驗給出的路徑是一個文件還是目錄
os.path.exists() 函數用來檢驗給出的路徑是否真地存在
os.curdir  返回當前目錄 ('.')
os.mkdir(path) 創建一個目錄
os.makedirs(path) 遞歸的創建目錄
os.chdir(dirname) 改變工作目錄到dirname    
os.path.getsize(name) 獲得文件大小,如果name是目錄返回0L
os.path.abspath(name) 獲得絕對路徑
os.path.normpath(path) 規范path字符串形式
os.path.splitext()  分離文件名與擴展名
os.path.join(path,name) 連接目錄與文件名或目錄
os.path.basename(path) 返回文件名
os.path.dirname(path) 返回文件路徑
os.walk(top,topdown=True,onerror=None)  遍歷迭代目錄
os.rename(src, dst)  重命名file或者directory src到dst 如果dst是一個存在的directory, 將拋出OSError. 在Unix, 如果dst在存且是一個file, 如果用戶有權限的話,它將被安靜的替換. 操作將會失敗在某些Unix 中如果src和dst在不同的文件系統中. 如果成功, 這命名操作將會是一個原子操作 (這是POSIX 需要). 在 Windows上, 如果dst已經存在, 將拋出OSError,即使它是一個文件. 在unix,Windows中有效。
os.renames(old, new) 遞歸重命名文件夾或者文件。像rename()

 

# shutil 模塊

shutil.copyfile( src, dst) 從源src復制到dst中去。當然前提是目標地址是具備可寫權限。拋出的異常信息為IOException. 如果當前的dst已存在的話就會被覆蓋掉
shutil.move( src, dst)  移動文件或重命名
shutil.copymode( src, dst) 只是會復制其權限其他的東西是不會被復制的
shutil.copystat( src, dst) 復制權限、最后訪問時間、最后修改時間
shutil.copy( src, dst)  復制一個文件到一個文件或一個目錄
shutil.copy2( src, dst)  在copy上的基礎上再復制文件最后訪問時間與修改時間也復制過來了,類似於cp –p的東西
shutil.copy2( src, dst)  如果兩個位置的文件系統是一樣的話相當於是rename操作,只是改名;如果是不在相同的文件系統的話就是做move操作
shutil.copytree( olddir, newdir, True/Flase)
把olddir拷貝一份newdir,如果第3個參數是True,則復制目錄時將保持文件夾下的符號連接,如果第3個參數是False,則將在復制的目錄下生成物理副本來替代符號連接
shutil.rmtree( src ) 遞歸刪除一個目錄以及目錄內的所有內容

  •  PART 2

Python語言中類似於Windows系統的dir命令的列出文件功能,然后描述如何測試一個文件名對應的是一個標准文件、目錄還是鏈接,以及提取文件大小和日期的方法。之后,我們還將介紹如何刪除文件和目錄,如何復制和刪除文件,以及怎樣將一個完整的文件路徑分解成目錄部分和文件名部分,最后,我們講解目錄的創建,以及如何在目錄樹中移動目錄並處理文件。

  一、顯示目錄內容

  當我們想要列出當前目錄中所有擴展名為.jpg或.gif的文件的時候,就可以使用glob模塊來完成此項任務,如下所示:

  import glob

  filelist = glob.glob(’*.jpg’) + glob.glob(’*.gif’)

  上述代碼使用了glob函數,該函數的參數為要顯示的文件類型。在這里,文件類型是通過類似UNIX操作系統shell風格通配符描述的一些文件名來指定的。這些通配符的使用方法,具體請參考fnmatch模塊的文檔,那里有具體的說明和示例。

  為了顯示一個目錄中的全部文件,可以使用如下所示的os.listdir函數:

  files = os.listdir(r’C:\hpl\scripting\src\py\intro’) #適用於 Windows

  files = os.listdir(’/home/hpl/scripting/src/py/intro’) # 適用於Unix

  # 跨平台版本:

  files = os.listdir(os.path.join(os.environ[’scripting’],

  ’src’, ’py’, ’intro’))

  files = os.listdir(os.curdir) # 當前目錄中的所有文件

  files = glob.glob(’*’) + glob.glob(’.*’)

 

  二、測試文件類型

  我們知道,文件名、目錄名和鏈接名都是用一個字符串作為其標識符的,但是給我們一個標識符,我們該如何確定它所指的到底是常規文件文件名、目錄名還是鏈接名呢?這時,我們可以使用os.path模塊提供的isfile函數、isdir函數和islink函數來達成我們的目標,如下所示:

  print myfile, ’是一個’,

  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)

  這里的時間以秒為單位,並且從1970年1月1日開始算起。為了獲取以天為單位的最后訪問日期,可以使用下列代碼:

  import time # time.time()返回當前時間

  age_in_days = (time.time()-time_of_last_access)/(60*60*24)

  為了獲取文件的詳細信息,可以使用os.stat函數和stat模塊中的其它實用程序來達到目的,如下:

  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)是一個常規文件,大小為 %(size)d 字節’ %\

  vars()

  有關stat模塊的詳細信息,請參見Python Library Reference。若想測試一個文件的讀、寫以及執行權限,可以用os.access函數,具體如下所示:

  if os.access(myfile, os.W_OK):

  print myfile, ’具有寫權限’

  if os.access(myfile, os.R_OK | os.W_OK | os.X_OK):

  print myfile, ’具有讀、寫以及執行權限’

  像上面這樣的測試代碼,對CGI腳本來說非常有用。

 

  三、文件和目錄的刪除

  若要刪除單個文件的話,可以使用os.remove函數,例如:os.remove(’mydata.dat’)。Os.remove的別名是os.unlink,不過后者跟傳統的UNIX操作系統以及Perl中清除文件的函數重名。我們可以使用下列方式來刪除一組文件,如所有以.jpg以及*.gif為擴展名的文件:

  for file in glob.glob(’*.jpg’) + glob.glob(’*.gif’):

  os.remove(file)

  大家知道,只有當目錄中內容已經被清空的時候,我們才可以使用rmdir命令來刪除該目錄。不過,我們經常想要刪除一個含有許多文件的目錄樹,這時我們可以使用shutil模塊提供的rmtree函數,如下所示:

shutil.rmtree(’mydir’)

  它相當於UNIX操作系統中的命令rm -rf mydir。

  我們可以建立一個自定義函數,使其在進行刪除操作的時候將文件和目錄做同等對待,其典型用法如下所示:

  remove(’my.dat’) #刪除當個文件my.dat

  remove(’mytree’) #刪除單個目錄樹 mytree

  # 通過字符串列表中的名稱來刪除多個文件/目錄樹:

  remove(glob.glob(’*.tmp’) + glob.glob(’*.temp’))

  remove([’my.dat’,’mydir’,’yourdir’] + glob.glob(’*.data’))

  下面是remove函數的實現:

  def remove(files):

  """刪除一個或多個文件和/或目錄。"""

  if isinstance(files, str): # files是個字符串嗎?

  files = [files] # 把files從字符串轉為列表

  if not isinstance(files, list): # files不是列表嗎?

  <report error>

  for file in files:

  if os.path.isdir(file):

  shutil.rmtree(file)

  elif os.path.isfile(file):

  os.remove(file)

  下面測試一下remove函數的靈活性:

  # 建立10個目錄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函數實現的一個注記,我們進行了下列測試:

  if not isinstance(files, list):

  它實際上是過於嚴厲。我們需要的只是一個被遍歷的一個文件/目錄名序列。實際上,我們並不關心名稱是否存儲在一個列表、元組或者數值數組中,所以更好的測試應該像下面這樣:

  if not operator.isSequenceType(files):

  <report error>

 

  四、文件的復制與重命名

  當我們要復制文件的時候,可以使用shutil模塊:

import shutil
shutil.copy(myfile, tmpfile)
#拷貝最后訪問時間和最后修改時間:
shutil.copy2(myfile, tmpfile)
# 拷貝一個目錄樹:
shutil.copytree(root_of_tree, destination_dir, True)

  Copytree的第三個參數規定對符號鏈接的處理,其中True表示保留符號鏈接;而False則意味着使用文件的物理副本替代符號鏈接。

  Python語言能夠很好地支持路徑名的跨平台組成:Os.path.join能使用正確的分界符(在UNIX和Mac OS X操作系統中使用/,在 Windows 上使用\)來聯接目錄和文件名,變量os.curdir和os.pardir分別表示當前工作目錄及其父目錄。 像下面的UNIX操作系統命令

cp ../../f1.c .

  可以使用Python語言提供一個跨平台的實現:

shutil.copy(os.path.join(os.pardir,os.pardir,’f1.c’), os.curdir)

  Os模塊中的rename函數通常被用於重命名一個文件:

os.rename(myfile, ’tmp.1’) # 將myfile重命名為’tmp.1’

  這個函數也可用來在相同的文件系統之內移動文件。這里,我們將myfile移動到目錄d下面:

os.rename(myfile, os.path.join(d, myfile))

  在跨文件系統移動文件的時候,可以先使用shutil.copy2來復制文件,然后再刪除原來的副本即可,如下:

  shutil.copy2(myfile, os.path.join(d, myfile))

  os.remove(myfile)

  后面這種移動文件的方法是最安全的。

 

  五、分解路徑名

  假設我們使用變量fname來存放一個包含完整路徑的文件名,例如:

/usr/home/hpl/scripting/python/intro/hw.py

  有時候,我們需要將這樣的文件路徑拆分為基本名稱hw.py和目錄名/usr/home/hpl/scripting/python/intro。在Python語言中,可以使用下列代碼達到目的:

  basename = os.path.basename(fname)

  dirname = os.path.dirname(fname)

  # 或

  dirname, basename = os.path.split(fname)

  擴展名是通過os.path.splitext函數提取出來的,

root, extension = os.path.splitext(fname)

  這樣,fname中的擴展名部分即.py被賦給變量extension,而其余部分則賦給了變量root。如果想得到不帶點號的擴展名的話,只需使用os.path.splitext(fname)[1][1:]即可。

  假設一個文件名為f,其擴展名隨意,若想將其擴展名改為ext,可以使用下面的代碼:

newfile = os.path.splitext(f)[0] + ext

  下面是一個具體的示例:

  >>> f = ’/some/path/case2.data_source’

  >>> moviefile = os.path.basename(os.path.splitext(f)[0] + ’.mpg’)

  >>> moviefile

  ’case2.mpg’

 

  六、目錄的創建和移動

  Os模塊中的函數mkdir可以用來創建目錄,而chdir函數則可以移動目錄,如下:

origdir = os.getcwd() # 將當前位置記下來
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’]) # 移到主目錄

  假設我們想要在自己的主目錄下創建一個新目錄py/src/test1,但是目前py、src和test1都不存在。如果使用mkdir命令來創建的話,需要使用三次才能建好這個嵌套的目錄,但是使用Python語言提供的os.makedirs命令的話,則無需這樣麻煩了,該命令可以一次建好整個目錄:

  os.makedirs(os.path.join(os.environ[’HOME’],’py’,’src’,’test1’))

 

  七、遍歷目錄樹

  下面的函數調用

os.path.walk(root, myfunc, arg)

  將遍歷root目錄樹;然后,對每個目錄名dirname分別調用myfunc(arg, dirname, files)即可,這里參數files是dir中的文件名列表(可通過調用os.listdir(dirname)來獲得);arg是用戶從調用代碼中傳遞來的參數。對於UNIX操作系統用戶來說,Python語言中跨平台的os.path.walk相當於Unix命令find。

  在解釋os.path.walk的用法的時候,人們常使用寫出主目錄中所有子目錄內的文件的名稱為例進行說明。當然,我們也可以在一個交互式的Python命令行中使用下列代碼段來體會os.path.walk的使用:

  def ls(arg, dirname, files):

  print dirname, ’has the files’, files

  os.path.walk(os.environ[’HOME’], ls, None)

  本例中,參數arg並非必需,所以在os.path.walk調用中讓其取值為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’

  現在,我們使用arg來建立一個數據結構,這里是一個2元組構成的列表,其中每個2元組存放文件的尺寸(以MB為單位)和完整的文件路徑。如果用於所有目錄的函數調用中都要更改arg的話,那么arg必須是一個可變的數據結構,即允許適當地進行修改。

  參數dirname是當前正在訪問的目錄的絕對路徑,而參數files內的文件名則是相對於dirname的相對路徑。在此期間,當前工作目錄並沒有改變,那就是說該腳本仍然呆在腳本啟動時刻所在的目錄中。這就是為什么我們需要把filepath弄成帶有dirname和file的絕對路徑的原因。若要改變當前工作目錄為dirname,只要在針對每個目錄調用os.path.walk的函數中調用一下os.chdir(dirname),然后在該函數的末尾重新調用os.chdir(dirname)將當前工作目錄改回原值即可,如下所示:

def somefunc(arg, dirname, files):
origdir = os.getcwd(); os.chdir(dirname)
<do tasks>
os.chdir(origdir)
os.path.walk(root, somefunc, arg)

  當然,如果您願意也可以編寫具有類似功能的代碼來替代os.path.walk。下面的代碼,將針對每個文件而非每個目錄來調用的自定義函數,如下所示:

def find(func, rootdir, arg=None):
# 對rootdir目錄中的每個文件調用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

  上面的函數find可以從scitools模塊中獲取。與內置函數os.path.walk相反,我們的find函數以大小寫敏感的字母順序來訪問文件和目錄。

  我們可以使用find函數來列出所有大於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

  參數arg帶來了巨大的靈活性。我們可以使用它來同時存放輸入數據和生成的數據結構。下一個范例將收集所有大於一定尺寸的帶有規定擴展名的文件的文件名和大小。輸出的結果按照文件大小排列。

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風格的通配符匹配
for s in arg[’extensions’]:
if fnmatch.fnmatch(ext, s):
treat_file = True # fullpath帶有正確的擴展名
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’]

  注意為列表排序的函數,bigfiles[’filelist’]函數中的每個元素就是一個字典,鍵size保存着一個字符串,不過在進行比較之前我們必須將單位Mb(最后兩個字符)去掉,並將其轉換為浮點數。

  八、小結

  對於文件和目錄的處理,雖然可以通過操作系統命令來完成,但是Python語言為了便於開發人員以編程的方式處理相關工作,提供了許多處理文件和目錄的內置函數。重要的是,這些函數無論是在Unix、Windows還是Macintosh平台上,它們的使用方式是完全一致的。本文詳細解釋了這些函數的使用方法,其中,我們首先介紹了顯示目錄內容的功能,然后描述如何測試一個文件名對應的是一個標准文件、目錄還是鏈接,以及提取文件大小和日期的方法。之后,我們還將介紹如何刪除文件和目錄,如何復制和刪除文件,以及怎樣將一個完整的文件路徑分解成目錄部分和文件名部分,最后,我們講解目錄的創建,以及如何在目錄樹中移動目錄並處理文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM