Python文本處理之按行處理大文件的方法
以行的形式讀出一個文件最簡單的方式是使用文件對象的readline()、readlines()和xreadlines()方法。
Python2.2+為這種頻繁的操作提供了一個簡化的語法——讓文件對象自身在行上高效迭代(這種迭代是嚴(yán)格的向前的)。
為了讀取整個文件,可能要使用read()方法,且使用字符串的split()來將它拆分WEIGHT行或其他塊。
下面是一些例子:
>>> for line in open('chap1.txt'): # Python 2.2+
... # process each line in some manner
... pass
...
>>> linelist = open('chap1.txt').readlines()
>>> print linelist[1849],
EXERCISE: Working with lines from a large file
>>> txt = open('chap1.txt').read()
>>> from os import linesep
>>> linelist2 = txt.split(linesep)
如果文件不大,讀取整個文件內(nèi)容也沒有關(guān)系。但如果是大文件,時間和內(nèi)存就是要重點(diǎn)關(guān)注的了。比如,復(fù)雜文檔或者活動日志文件,通常有上M,甚至很多G的大小。就算這些文件的內(nèi)容沒有超出可用內(nèi)存的尺寸,讀取他們?nèi)匀皇窍喈?dāng)耗時的。
很明顯,如果你需要處理文件的每一行,那就必須讀取整個文件;如果可以按序列處理,xreadlines方法是一種更節(jié)約內(nèi)存的方法。但是對于那些僅僅需要一個大文件的一部分行的應(yīng)用,要獲得提高其實(shí)并不難。對于這一點(diǎn),模塊“l(fā)inecache”非常合適。
具有緩存功能的行列表
使用linecache可以直接從一個文件中讀取指定行:
>>> import linecache
>>> print linecache.getline('chap1.txt',1850),
PROBLEM: Working with lines from a large file
記住,linecache.getline()的計(jì)數(shù)是從1開始的。
如果有一個即具有“l(fā)inecache”的效率,又有列表的一些功能的對象就好了。這個對象不僅可以枚舉和索引,同時還支持切片。
#------------------ cachedlinelist.py --------------------#
import linecache, types
class CachedLineList:
# Note: in Python 2.2+, it is probably worth including:
# __slots__ = ('_fname')
# ...and inheriting from 'object'
def __init__(self, fname):
self._fname = fname
def __getitem__(self, x):
if type(x) is types.SliceType:
return [linecache.getline(self._fname, n+1)
for n in range(x.start, x.stop, x.step)]
else:
return linecache.getline(self._fname, x+1)
def __getslice__(self, beg, end):
# pass to __getitem__ which does extended slices also
return self[beg:end:1]
使用這個新對象幾乎和使用一個由“open(fname).readlines()”創(chuàng)建的列表一樣。除了它的效率要更高之外(特別是在內(nèi)存使用方面):
>>> from cachedlinelist import CachedLineList
>>> cll = CachedLineList('../chap1.txt')
>>> cll[1849]
' PROBLEM: Working with lines from a large file\r\n'
>>> for line in cll[1849:1851]: print line,
...
PROBLEM: Working with lines from a large file
----------------------------------------------------------
>>> for line in cll[1853:1857:2]: print line,
...
a matter of using the '.readline()', '.readlines()' and
simplified syntax for this frequent operation by letting the
隨機(jī)行
有時候,特別是為了測試,可能需要檢查某些典型的行。人們很容易就誤認(rèn)為一個對文本的前面幾行和后面幾行有效的處理就能適用任何其他地方。很不幸,很多文件的前幾行和最后幾行通常都是非典型的:有時候是消息頭或注腳,有時候可能是開發(fā)時的日志文件的前幾行等等。窮舉測試整個文件并不是你想要的,通常這樣也非常的耗時。
在大多數(shù)系統(tǒng)上,查找一個文件中的特定位置要比讀出該位置前的所有內(nèi)容直到到達(dá)該位置快的多。
就算使用linecache,要到達(dá)緩存行,你也需要一個字節(jié)一個字節(jié)的讀取前面的內(nèi)容。從一個大文件中找隨機(jī)行的最快的方式是,先找到一個隨機(jī)位置,然后讀取該位置相對前后的少數(shù)字節(jié)。
#-------------------- randline.py ------------------------#
#!/usr/bin/python
"""Iterate over random lines in a file (req Python 2.2+)
From command-line use: % randline.py <fname> <numlines>
"""
import sys
from os import stat, linesep
from stat import ST_SIZE
from random import randrange
MAX_LINE_LEN = 4096
#-- Iterable class
class randline(object):
__slots__ = ('_fp','_size','_limit')
def __init__(self, fname, limit=sys.maxint):
self._size = stat(fname)[ST_SIZE]
self._fp = open(fname,'rb')
self._limit = limit
def __iter__(self):
return self
def next(self):
if self._limit <= 0:
raise StopIteration
self._limit -= 1
pos = randrange(self._size)
priorlen = min(pos, MAX_LINE_LEN) # maybe near start
self._fp.seek(pos-priorlen)
# Add extra linesep at beg/end in case pos at beg/end
prior = linesep + self._fp.read(priorlen)
post = self._fp.read(MAX_LINE_LEN) + linesep
begln = prior.rfind(linesep) + len(linesep)
endln = post.find(linesep)
return prior[begln:]+post[:endln]
#-- Use as command-line tool
if __name__=='__main__':
fname, numlines = sys.argv[1], int(sys.argv[2])
for line in randline(fname, numlines):
print line
關(guān)于上面的實(shí)現(xiàn),需要注意以下細(xì)節(jié):
(1)在行迭代中,相同的行可能會被多次選中。當(dāng)然,如果你只是從大文件中選很少行的話,這種情況通常不會出現(xiàn)。
(2)既然是選中包含隨機(jī)位置的行,那就意味著更 有可能選擇長的行(譯注:這是為什么?沒有明白)。
本文翻譯自Text Processing in Python
中“PROBLEM: Working with lines from a large file”
以上這篇Python文本處理之按行處理大文件的方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談django框架集成swagger以及自定義參數(shù)問題
這篇文章主要介紹了淺談django框架集成swagger以及自定義參數(shù)問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Python Socket庫基礎(chǔ)方法與應(yīng)用詳解
這篇文章主要介紹了關(guān)于Python socket庫的詳細(xì)技術(shù)解析,包含基礎(chǔ)方法說明、工作原理剖析,以及多個應(yīng)用領(lǐng)域的完整實(shí)現(xiàn)代碼,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2025-04-04
使用Python實(shí)現(xiàn)提取PDF文件中指定頁面的內(nèi)容
在日常工作和學(xué)習(xí)中,我們經(jīng)常需要從PDF文件中提取特定頁面的內(nèi)容,本文主要為大家詳細(xì)介紹了如何使用Python編程語言和兩個強(qiáng)大的庫——pymupdf和wxPython來實(shí)現(xiàn)這個任務(wù),需要的可以了解下2023-12-12
利用Tkinter和matplotlib兩種方式畫餅狀圖的實(shí)例
下面小編就為大家?guī)硪黄肨kinter和matplotlib兩種方式畫餅狀圖的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望對大家有所幫助2017-11-11

