读BitTorrent码日记6

# 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()
#下面有是一堆测试函数,这里让我想起了测试驱动开发,大约在今天过年时接触过它,
#现在这种方式在一个开放源码的软件中得以应用,开始学习在自己的程序中学习使用它......
#(待续)

你可能感兴趣的:(读BitTorrent码日记6)