# Written by Bram Cohen
# See license.txt for license information
# File name: storage. py
# Code reading diary: 2004-9-9
# Pen: zfive5
#
# Analysis storage class mainly responsible for data storage operations
#
From Sha import Sha
From bisect import bisect_right
# Data Storage Operations
Class storage:
# Constructor
Def _ init _ (self, files, open, exists, getsize ):
# Can Raise ioerror and valueerror
Self. Ranges = []
Total = 0l
So_far = 0l
# Initialize the range list here. Here, the file name and the proportion of the file in the total download size, for example (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 ):
# If the file size is zero, an empty file is generated.
Open (file, 'wb '). Close ()
# Start file size list
Self. Begins = [I [0] For I in self. Ranges]
Self. total_length = Total
Self. Handles = {}
Self. whandles = {}
Self. Tops = {}
# Assign a value to the file handle
For file, length in files:
If exists (File ):
# If the file has not been downloaded, open the file in append mode.
L = getsize (file)
If l! = Length:
Self. Handles = open (file, 'rb + ')
# Write count mark
Self. whandles = 1
If l> length:
# Force file size to length
Self. Handles. truncate (length)
Else:
# Open the file in read-only mode. The file has been downloaded.
Self. Handles = open (file, 'rb ')
Self. Tops = L
Else:
# Create and open a file if the file does not exist
Self. Handles = open (file, 'wb + ')
Self. whandles = 1
# Determine whether the space has been allocated
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
# Set the file to read-only
Def set_readonly (Self ):
# May raise ioerror or oserror
For file in self. whandles. Keys ():
Old = self. Handles
Old. Flush ()
Old. Close ()
Self. Handles = open (file, 'rb ')
# Get the total download size
Def get_total_length (Self ):
Return self. total_length
# Obtain all inclusive pos-> amount files, starting and ending locations
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
# Read data from the total data at the beginning and end of the data
Def read (self, POs, amount ):
R = []
For file, POs, end in self. _ intervals (Pos, amount ):
H = self. Handles
H. Seek (POS)
R. append (H. Read (end-Pos ))
Return ''. Join (r)
# Write Data in the total data to the space within the starting and ending positions
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. Close ()
Self. Handles = open (file, 'rb + ')
Self. whandles = 1
H = self. Handles
H. Seek (BEGIN)
H. Write (s [Total: Total + end-begin])
Total + = end-begin
# Close all file handles
Def close (Self ):
For H in self. Handles. Values ():
H. Close ()
# Below are a bunch of test functions, which reminds me of test-driven development. I came into contact with it about the Chinese New Year,
# Now this method can be applied in an open-source software and started to learn how to use it in your own program ......
# (To be continued)