Python文本處理之按行處理大文件的方法
以行的形式讀出一個(gè)文件最簡(jiǎn)單的方式是使用文件對(duì)象的readline()、readlines()和xreadlines()方法。
Python2.2+為這種頻繁的操作提供了一個(gè)簡(jiǎn)化的語(yǔ)法——讓文件對(duì)象自身在行上高效迭代(這種迭代是嚴(yán)格的向前的)。
為了讀取整個(gè)文件,可能要使用read()方法,且使用字符串的split()來(lái)將它拆分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)
如果文件不大,讀取整個(gè)文件內(nèi)容也沒(méi)有關(guān)系。但如果是大文件,時(shí)間和內(nèi)存就是要重點(diǎn)關(guān)注的了。比如,復(fù)雜文檔或者活動(dòng)日志文件,通常有上M,甚至很多G的大小。就算這些文件的內(nèi)容沒(méi)有超出可用內(nèi)存的尺寸,讀取他們?nèi)匀皇窍喈?dāng)耗時(shí)的。
很明顯,如果你需要處理文件的每一行,那就必須讀取整個(gè)文件;如果可以按序列處理,xreadlines方法是一種更節(jié)約內(nèi)存的方法。但是對(duì)于那些僅僅需要一個(gè)大文件的一部分行的應(yīng)用,要獲得提高其實(shí)并不難。對(duì)于這一點(diǎn),模塊“l(fā)inecache”非常合適。
具有緩存功能的行列表
使用linecache可以直接從一個(gè)文件中讀取指定行:
>>> import linecache >>> print linecache.getline('chap1.txt',1850), PROBLEM: Working with lines from a large file
記住,linecache.getline()的計(jì)數(shù)是從1開(kāi)始的。
如果有一個(gè)即具有“l(fā)inecache”的效率,又有列表的一些功能的對(duì)象就好了。這個(gè)對(duì)象不僅可以枚舉和索引,同時(shí)還支持切片。
#------------------ 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]
使用這個(gè)新對(duì)象幾乎和使用一個(gè)由“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ī)行
有時(shí)候,特別是為了測(cè)試,可能需要檢查某些典型的行。人們很容易就誤認(rèn)為一個(gè)對(duì)文本的前面幾行和后面幾行有效的處理就能適用任何其他地方。很不幸,很多文件的前幾行和最后幾行通常都是非典型的:有時(shí)候是消息頭或注腳,有時(shí)候可能是開(kāi)發(fā)時(shí)的日志文件的前幾行等等。窮舉測(cè)試整個(gè)文件并不是你想要的,通常這樣也非常的耗時(shí)。
在大多數(shù)系統(tǒng)上,查找一個(gè)文件中的特定位置要比讀出該位置前的所有內(nèi)容直到到達(dá)該位置快的多。
就算使用linecache,要到達(dá)緩存行,你也需要一個(gè)字節(jié)一個(gè)字節(jié)的讀取前面的內(nèi)容。從一個(gè)大文件中找隨機(jī)行的最快的方式是,先找到一個(gè)隨機(jī)位置,然后讀取該位置相對(duì)前后的少數(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)在行迭代中,相同的行可能會(huì)被多次選中。當(dāng)然,如果你只是從大文件中選很少行的話,這種情況通常不會(huì)出現(xiàn)。
(2)既然是選中包含隨機(jī)位置的行,那就意味著更 有可能選擇長(zhǎng)的行(譯注:這是為什么?沒(méi)有明白)。
本文翻譯自Text Processing in Python
中“PROBLEM: Working with lines from a large file”
以上這篇Python文本處理之按行處理大文件的方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Python使用email模塊對(duì)郵件進(jìn)行編碼和解碼的實(shí)例教程
- Python簡(jiǎn)單實(shí)現(xiàn)Base64編碼和解碼的方法
- Python中json格式數(shù)據(jù)的編碼與解碼方法詳解
- Python base64編碼解碼實(shí)例
- 對(duì)python中url參數(shù)編碼與解碼的實(shí)例詳解
- 詳解Python中的文本處理
- Python實(shí)現(xiàn)簡(jiǎn)單文本字符串處理的方法
- python處理文本文件并生成指定格式的文件
- Python處理文本文件中控制字符的方法
- Python編解碼問(wèn)題及文本文件處理方法詳解
相關(guān)文章
Python設(shè)計(jì)模式之享元模式原理與用法實(shí)例分析
這篇文章主要介紹了Python設(shè)計(jì)模式之享元模式原理與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了享元模式的相關(guān)概念、原理、定義及使用方法,需要的朋友可以參考下2019-01-01python框架Django實(shí)戰(zhàn)商城項(xiàng)目之工程搭建過(guò)程圖文詳解
這篇文章主要介紹了python框架Django實(shí)戰(zhàn)商城項(xiàng)目之工程搭建過(guò)程,這個(gè)項(xiàng)目很像京東商城,項(xiàng)目開(kāi)發(fā)采用前后端不分離的模式,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-03-03PyTorch基礎(chǔ)之torch.nn.CrossEntropyLoss交叉熵?fù)p失
這篇文章主要介紹了PyTorch基礎(chǔ)之torch.nn.CrossEntropyLoss交叉熵?fù)p失講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Python+OpenCV實(shí)戰(zhàn)之實(shí)現(xiàn)文檔掃描
這篇文章主要為大家詳細(xì)介紹了Python+Opencv如何實(shí)現(xiàn)文檔掃描的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-09-09Python不改變Excel單元格樣式方式—xls和xlsx兩種格式
這篇文章主要介紹了Python不改變Excel單元格樣式方式—xls和xlsx兩種格式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Python面向?qū)ο蟪绦蛟O(shè)計(jì)類的封裝與繼承用法示例
這篇文章主要介紹了Python面向?qū)ο蟪绦蛟O(shè)計(jì)類的封裝與繼承用法,結(jié)合實(shí)例形式分析了Python面向?qū)ο蟪绦蛟O(shè)計(jì)中類的封裝、繼承相關(guān)概念、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2019-04-04基于Python pip用國(guó)內(nèi)鏡像下載的方法
今天小編就為大家分享一篇基于Python pip用國(guó)內(nèi)鏡像下載的方法。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06