Python Cookbook-2.14 回退输入文件到起点
任务
需要创建一个输入文件对象(数据可能来自于网络socket 或者其他输入文件句柄),此文件对象允许回退到起点,这样就可以完全读取其中所有数据。
解决方案
将文件对象封装到一个合适的类中:
将文件对象封装到一个合适的类中:
from cStringIO import StringIO
class RewindableFile(obiect):
'''封装一个文件句柄以便重定位到开始位置'''
def __init__(self,input_file):
#将input_file 封装到一个支持回退的类文件对象中#
self.file = input_file
self.buffer_file = StringIO()
self.at_start = True
try :
self.start = input_file.tell()
except(IOError,AttributeError):
self.start = 0
self,use_buffer = True
def seek(self,offset,whence = 0):
'''根据给定的字节定位。
必须:whence == 0 and offset == self.start
'''
if whence != 0:
raise ValueError("whence = %r;expecting 0" %(whence,))
if offset != 0
raise ValueError("offset = %r;expecting %s" %(offset,self.start))
self.rewind()
def rewind(self):
'''回到起始位置'''
self.buffer_file.seek(0)
self.at_start = True
def tell(self):
'''返回文件的当前位置(必须在开始处)'''
if not self.at_start:
raise TypeError("RewindableFile can't tell except at start of file")
return self.start
def _read(self,size):
if size < 0:#一直读到文件末尾
y = self.file.read()
if self._use_buffer:
self.buffer_file.write(y)
return self.buffer_file.read() + y
elif size == 0:#不必读空字符串
return "
x= self.buffer_file.read(size)
if len(x) < size:
y = self.file.read(size - len(x))
if self._use_buffer:
self.buffer_file.write(y)
return x + y
return x
def read(self,size = -1):
'''根据size指定的大小读取数据
默认为-1,意味着一直读到文件结束
'''
x = self.read(size)
if self.at_start and x:
self.at_start = False
self._check_no__buffer()
return x
def readline(self):
'''从文件中读取一行'''
# buffer_file中有吗?
s =self.buffer_file.readline()
if s[-1:] == "\n":
return s
#没有,从输入文件中读取一行
t = self.file.readline()
if self._use_buffer:
self.buffer_file.write(t)
self._check_no_buffer()
return s + t
def readlines(self):
'''读取文件中所有剩余的行'''
return self.read().splitlines(True)
def _check_no_buffer(self):
#如果"nobuffer"被调用,而且我们也完成了对缓存文件的处理
#那就删掉缓存,把所有的东西都重定向到原来的输入文件
if not self._use_buffer and self.buffer_file.tell() == len(self.buffer_file.getvalue()):
#为了获得尽可能高的性能,我们重新绑定了self中的所有相关方法
for n in'seek tell read readline readlines',split():
setattr(self,n,getattr(self.file,n,None))
del self.buffer_file
def nobuffer(self):
'''通知 Rewindablerile,一旦缓存耗尽就停止继续使用缓存'''
self._use_buffer = False
讨论
太长了,此处省略。