用Python對體積較大的CSV文件進行比較的經驗 » 進化的測試 | 進化的測試
八 03 2010最近的工作總是跟數據打交道,需要經常比較一些CSV文件,這些CSV文件其實都需要被LOAD到數據庫里面,所以也就是一堆堆的數據文件需要比較。暫時沒有發現有比較好用的現成的CSV比較工具,自己動手用Python做了一個湊合能用的。思想比較簡單,就是把CSV文件的內容讀取出來,保存為一個list,然后把2個CSV文件所生成的list進行對比。有個特殊的需求,就是對於CSV文件中一些肯定不一樣的列,例如process date這樣的字段,是需要跳過的。由於本地生成的CSV文件比較小,剛開始沒有注意到如果文件太大的話會占用很多的內存。最開始的版本是:
def readcsv2list(filename, rows): fileobj = open(filename, 'rb') csvreader = csv.reader(fileobj) retlist = [] for row in csvreader: clist = [] selected_rows = [ic for ic in range(len(row)) if ic not in rows] for c in selected_rows: clist.append(row[c]) retlist.append(clist) fileobj.close() return retlist后來用這個腳本比較生產環境數據的時候就遇到問題了,其中最大的一個數據文件大概是1.5GB,這只是文件大小,把文件轉成list以后所占用的內存會翻幾倍(這個很容易理解,整數1在文件里面站1個字節,放到list里面就要4個字節了)。一下子把機器的內存用光了。隨后找了一下文檔,csv.reader是沒有一個方法可以指定一次讀取若干行數據的。后來就利用file object有一個readline()方法,通過一個參數來控制一次讀取多少行的記錄,從而達到控制內存使用量的目的。需要的注意的點有:1. 在讀完若干行數據以后,需要獲取一下當前這個file object的位置,Python提供了.tell()方法來獲取這個值;2. 讀取文件的時候需要知道上一會讀到什么地方了,並且從那里繼續往下讀,用到了.seek()方法;3. readline()方法在讀到文件末尾的時候只會返回一個空字符,所以需要對這個空字符做一點處理。
def readcsv2list(filename, rows, last_position, max_line): fileobj = open(filename, 'rb') fileobj.seek(last_position) datalines = [] for i in range(max_line): line_itme = fileobj.readline() if len(line_itme) > 0: datalines.append(line_itme) else: break csvreader = csv.reader(datalines) retlist = [] for row in csvreader: clist = [] selected_rows = [ic for ic in range(len(row)) if ic not in rows] for c in selected_rows: clist.append(row[c]) retlist.append(clist) current_position = fileobj.tell() fileobj.close() return retlist, current_positionPython,尤其是低版本(例如我們用的2.4.3),對於在程序里面顯式地del一些變量(通常是個大list之類),是不會立刻釋放內存的,所以對於處理數據量比較大的case的時候就需要特別注意內存的使用。參考文章:
Python Memory Management
Why doesn’t Python release the memory when I delete a large object?
