# Written by Bram Cohen
# see LICENSE.txt for license information
#文件名称:Storage.py
#读码日记:2004-9-9
#笔 者:zfive5(醉马不肖 之 [孤舟蓑笠翁, 独钓寒江雪])
#
# 分析Storage类 主要负责数据存储操作的类
#
from sha import sha
from bisect import bisect_right
#数据存储操作类
class Storage:
#构造函数
def __init__(self, files, open, exists, getsize):
# can raise IOError and ValueError
self.ranges = []
total = 0l
so_far = 0l
#这里初始化range列表,这里文件名称,文件在总的下载大小中所在的比例,例如 (10--1000)
for file, length in files:
if length != 0:
self.ranges.append((total, total + length, file))
total += length
if exists(file):
l = getsize(file)
if l > length:
l = length
so_far += l
elif not exists(file):
#如果这个文件大小为零就生成一个空的文件.
open(file, 'wb').close()
#开始文件大小列表
self.begins = [i[0] for i in self.ranges]
self.total_length = total
self.handles = {}
self.whandles = {}
self.tops = {}
#对文件句柄进行赋值
for file, length in files:
if exists(file):
#如果文件没有下载完毕,以追加方式打开文件
l = getsize(file)
if l != length:
self.handles[file] = open(file, 'rb+')
#写记数标志
self.whandles[file] = 1
if l > length:
#强制文件大小为length
self.handles[file].truncate(length)
else:
#只读方式打开文件,文件下载完毕
self.handles[file] = open(file, 'rb')
self.tops[file] = l
else:
#如果文件不存在就生成,创建并打开文件
self.handles[file] = open(file, 'wb+')
self.whandles[file] = 1
#判断空间是否已经分配
def was_preallocated(self, pos, length):
for file, begin, end in self._intervals(pos, length):
if self.tops.get(file, 0) < end:
return False
return True
#设置文件为只读状态
def set_readonly(self):
# may raise IOError or OSError
for file in self.whandles.keys():
old = self.handles[file]
old.flush()
old.close()
self.handles[file] = open(file, 'rb')
#得到总下载大小
def get_total_length(self):
return self.total_length
#得到pos->amount的所有包容的文件,起止位置
def _intervals(self, pos, amount):
r = []
stop = pos + amount
p = bisect_right(self.begins, pos) - 1
while p < len(self.ranges) and self.ranges[p][0] < stop:
begin, end, file = self.ranges[p]
r.append((file, max(pos, begin) - begin, min(end, stop) - begin))
p += 1
return r
#从总数据里读数据起止位置范围内的数据
def read(self, pos, amount):
r = []
for file, pos, end in self._intervals(pos, amount):
h = self.handles[file]
h.seek(pos)
r.append(h.read(end - pos))
return ''.join(r)
#在总数据里写数据到起止位置范围内的空间里
def write(self, pos, s):
# might raise an IOError
total = 0
for file, begin, end in self._intervals(pos, len(s)):
if not self.whandles.has_key(file):
self.handles[file].close()
self.handles[file] = open(file, 'rb+')
self.whandles[file] = 1
h = self.handles[file]
h.seek(begin)
h.write(s[total: total + end - begin])
total += end - begin
#关闭所有文件句柄
def close(self):
for h in self.handles.values():
h.close()
#下面有是一堆测试函数,这里让我想起了测试驱动开发,大约在今天过年时接触过它,
#现在这种方式在一个开放源码的软件中得以应用,开始学习在自己的程序中学习使用它......
#(待续)