-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a type of DownloadFile that can be split
This allows Kolibri to create content nodes from arbitrarily large source files for certain types of content.
- Loading branch information
1 parent
a74e193
commit e3cfde3
Showing
3 changed files
with
189 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
class FileSlice(object): | ||
""" | ||
File-like object that represents a slice of a file, starting from its | ||
current offset until `count`. Reads are always relative to the slice's | ||
start and end point. | ||
""" | ||
|
||
def __init__(self, file, count=None): | ||
self.file = file | ||
self.start = file.tell() | ||
|
||
file.seek(0, 2) | ||
self.file_size = file.tell() | ||
|
||
if count is None: | ||
count = self.file_size | ||
|
||
count = min(self.file_size - self.start, count) | ||
self.end = self.start + count | ||
|
||
# Seek to the end of the file so the next FileSlice object will be | ||
# created from that point. | ||
file.seek(self.end) | ||
|
||
self.__last_offset = self.start | ||
|
||
@classmethod | ||
def from_file(cls, file, chunk_size): | ||
slice = cls(file, chunk_size) | ||
yield slice | ||
|
||
while slice.end < slice.file_size: | ||
slice = cls(file, chunk_size) | ||
yield slice | ||
|
||
@property | ||
def size(self): | ||
return self.end - self.start | ||
|
||
def seek(self, offset, whence=0): | ||
if whence == 0: | ||
offset = self.start + offset | ||
elif whence == 1: | ||
offset = self.tell() + offset | ||
elif whence == 2: | ||
offset = self.end - offset | ||
self.file.seek(offset) | ||
self.__store_offset() | ||
|
||
def __reset_offset(self): | ||
if self.file.tell() != self.__last_offset: | ||
self.file.seek(self.__last_offset) | ||
|
||
def __store_offset(self): | ||
self.__last_offset = self.file.tell() | ||
|
||
def tell(self): | ||
self.__reset_offset() | ||
return self.file.tell() - self.start | ||
|
||
def read(self, count=None): | ||
self.__reset_offset() | ||
|
||
if count is None: | ||
count = self.size | ||
|
||
remaining = max(0, self.size - self.tell()) | ||
|
||
buffer = self.file.read(min(count, remaining)) | ||
self.__store_offset() | ||
return buffer | ||
|
||
def write(self, string): | ||
raise NotImplementedError() |