Python 按行讀取文字檔案 快取 和 非快取實現
需求
最近專案中有個讀取檔案的需求,資料量還挺大,10萬行的數量級。
java 使用快取讀取檔案是,會相應的建立一個內部緩衝區陣列在java虛擬機器記憶體中,因此每次處理的就是這一整塊記憶體。
簡單的想:就是如果不用快取,每次都要硬碟–虛擬機器快取–讀取;有了快取,提前讀了一段放在虛擬機器快取裡,可以避免頻繁將硬碟上的資料讀到快取裡。
因為對記憶體的操作肯定是比硬碟的操作要快的。
對了,java還有對映記憶體,可以解決大檔案讀寫的問題。
思路
大檔案讀寫不能一次全部讀入記憶體,這樣會導致耗盡記憶體。(但是在記憶體允許的情況下,全部讀入記憶體是不是速度更快??)
對於大檔案可以一行一行讀取,因為我們處理完這行,就可以把它拋棄。
我們也可以一段一段讀取大檔案,實現一種快取處理。每次讀取一段檔案,將這段檔案放在快取裡,然後對這段處理。這會比一行一行快些。
方法1:一行一行讀取
我們可以開啟一個檔案,然後用for迴圈讀取每行,比如:
def method1(newName):
s1 = time.clock()
oldLine = '0'
count = 0
for line in open(newName):
newLine = line
if (newLine != oldLine):
#判斷是不是空行
if newLine.strip():
nu = newLine.split()[0]
oldLine = newLine
count += 1
print "deal %s lines" %(count)
e1 = time.clock()
print "cost time " + str(e1-s1)
我們測試一下
fileName = 'E:\\pythonProject\\ruisi\\correct_re.txt'
method1(fileName)
輸出
deal 218376 lines
cost time 0.288900734402
方法1.1 一行一行讀取的變形
def method11(newName):
s1 = time.clock()
oldLine = '0'
count = 0
file = open(newName)
while 1:
line = file.readline()
if not line:
break
else:
if line.strip():
newLine = line
if (newLine != oldLine):
nu = newLine.split()[0]
oldLine = newLine
count += 1
print "deal %s lines" %(count)
e1 = time.clock()
print "cost time " + str(e1-s1)
deal 218376 lines
cost time 0.371977884619
耗時和方法1差不多,比方法1稍微多些。
方法2:一行一行,使用fileinput模組
def method2(newName):
s1 = time.clock()
oldLine = '0'
count = 0
for line in fileinput.input(newName):
newLine = line
if newLine.strip():
if (newLine != oldLine):
nu = newLine.split()[0]
oldLine = newLine
count += 1
print "deal %s lines" %(count)
e1 = time.clock()
print "cost time " + str(e1-s1)
deal 218376 lines
cost time 0.514534051673
這兒的耗時差不多是方法1的兩倍。
藉助快取,每次讀取1000行
def method3(newName):
s1 = time.clock()
file = open(newName)
oldLine = '0'
count = 0
while 1:
lines = file.readlines(10*1024)
#print len(lines)
if not lines:
break
for line in lines:
if line.strip():
newLine = line
if (newLine != oldLine):
nu = newLine.split()[0]
oldLine = newLine
count += 1
print "deal %s lines" %(count)
e1 = time.clock()
Note
readlinessizehint() 引數是限定位元組大小,不是行數。
注意預設有個內部緩衝區大小是8KB,如果設定值小於 8*1024。那麼都是按照8KB來的。print len(lines)
輸出大概都為290。
只有當設定值大於8KB,上面的print len(lines)
才會發生變化。
deal 218376 lines
cost time 0.296652349397
這兒的效能還沒方法1,表現好。可以調整每次讀取的行數,比如500,1000等等,可以達到不同的耗時。
方法4 一次性全部讀到記憶體裡
def method4(newName):
s1 = time.clock()
file = open(newName)
oldLine = '0'
count = 0
for line in file.readlines():
if line.strip():
newLine = line
if (newLine != oldLine):
nu = newLine.split()[0]
oldLine = newLine
count += 1
print "deal %s lines" %(count)
e1 = time.clock()
print "cost time " + str(e1-s1)
輸出
deal 218376 lines
cost time 0.30108883108
結論
推薦使用
with open('foo.txt', 'r') as f:
for line in f:
# do_something(line)
對於大檔案可以使用索引,這個索引記錄下每行開頭的位置,之後就可以用file.seek()定位了。如果檔案內容修改了,還需要重新建立索引。這個索引可以有很多種方法建立,但是都需要將檔案遍歷一次。