2012年1月30日

Python 遞迴處理路徑下檔案與資料夾

取得某個路徑下的所有檔案與資料夾是經常會使用到的功能,尤其是在寫一些小工具來處理硬碟上的檔案時。早先我都是用傳統寫 C++ 的方式來思考,所以在 Python 的文件中找到了 listdir() 這個函式,然後寫了類似以下的代碼:

import os

def doInDir(somedir):
    print somedir
    fileList = os.listdir(somedir)
    for f in fileList:
        fullpath = os.path.join(somedir, f)
        if os.path.isdir(fullpath):
            doInDir(fullpath)
        elif os.path.isfile(fullpath):
            print fullpath

doInDir("/tmp/")

不過最近發現在 Python 下做事其實可以更簡單,內建的 os.walk() 就提供了非常強大的功能,使用的方式如下:

import os

for root, dirs, files in os.walk("/tmp/"):
    print root
    for f in files:
        print os.path.join(root, f)

相比之下,同樣的功能用 os.walk() 就精簡了許多。上面兩段程式碼做的事情基本上是一樣的,都是列出指定資料夾下的所有檔案與子資料夾;不過有個小小地方需要注意一下,就是用兩種方法索處理的內部順序並不相同。listdir() 會按照深度優先搜索的順序,一層一層往下深入,其中檔案與資料夾的先後順序是交替穿插的;而 os.walk() 因為把檔案與文件夾都歸類好放在各自的 list 中,因此兩者的處理是分開的。以下是上面兩段程式針對同一個範例資料夾的輸出,可以看出處理順序的不同。

os.walk()
/testtree/
/testtree/1file
/testtree/3file
/testtree/2dir
/testtree/2dir/21file
/testtree/2dir/24file
/testtree/2dir/22dir
/testtree/2dir/22dir/221file
/testtree/2dir/23dir
/testtree/4dir

os.listdir()
/testtree/
/testtree/1file
/testtree/2dir
/testtree/2dir/21file
/testtree/2dir/22dir
/testtree/2dir/22dir/221file
/testtree/2dir/23dir
/testtree/2dir/24file
/testtree/3file
/testtree/4dir
2012年1月24日

Python 計算檔案的 CRC32 驗證碼

用 Python 計算 CRC32 很簡單,只要使用內建的 binascii 模組即可。
import binascii
print binascii.crc32("hello world")
要反覆計算的話,可以用:
crc = binascii.crc32("hello")
crc = binascii.crc32(" world", crc)
其中的第二行,將前一步驟所計算的 CRC 結果作為參數再次傳入函式中。


如果要計算檔案的 CRC32,可以透過以下函式來計算:
import binascii
def computeFileCRC(filename):
    try:
        blocksize = 1024 * 64
        f = open(filename, "rb")
        str = f.read(blocksize)
        crc = 0
        while len(str) != 0:
            crc = binascii.crc32(str,crc) & 0xffffffff
            str = f.read(blocksize)
        f.close()
    except:
        print "compute file crc failed!"
        return 0
    return crc

上面比較特別要注意的是這行:
crc = binascii.crc32(str,crc) & 0xffffffff
根據官方文件,在 Python 2.x 的版本中,binascii.crc32 所計算出來的 CRC 值域為 [-2^31, 2^31-1] 之間的有號整數,為了要與一般 C 所實作的 CRC 結果作比對,需要將其轉為無號整數,所以加上「& 0xffffffff」這段來做轉換。如果是 Python 3.x 的版本,其計算結果為 [0, 2^32-1] 間的無號整數,因此不需額外加上修正。


另外,上述 computeFileCRC 計算的結果為十進位整數,而通常見到的 CRC32 字串會以 16 進位方式表示,所以可以這樣轉換:
crcstr = hex(computeFileCRC("somefile"))[2:]
或是,如果要直接使用在字串中,也可以用 format 的方式轉換成 16 進位格式:
print ("crc32: %08x" % computeFileCRC("somefile"))
Related Posts Plugin for WordPress, Blogger...