Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions bottle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2776,32 +2776,39 @@ def filename(self):
fname = re.sub(r'[-\s]+', '-', fname).strip('.-')
return fname[:255] or 'empty'

def _copy_file(self, fp, chunk_size=2 ** 16):
def _copy_file(self, fp, chunk_size=2 ** 16, max_size=None):
read, write, offset = self.file.read, fp.write, self.file.tell()
while 1:
buf = read(chunk_size)
if not buf: break
if max_size is not None:
max_size -= len(buf) # Last chunk may be smaller than chunk_size
if max_size < 0:
raise IOError('File size exceeds maximum size.')
write(buf)
self.file.seek(offset)

def save(self, destination, overwrite=False, chunk_size=2 ** 16):
def save(self, destination, overwrite=False, chunk_size=2 ** 16,
max_size=None):
""" Save file to disk or copy its content to an open file(-like) object.
If *destination* is a directory, :attr:`filename` is added to the
path. Existing files are not overwritten by default (IOError).

:param destination: File path, directory or file(-like) object.
:param overwrite: If True, replace existing files. (default: False)
:param chunk_size: Bytes to read at a time. (default: 64kb)
:param max_size: If not None: Maximum number of bytes to write.
If exceeded by file size, raise IOError. (default: None)
"""
if isinstance(destination, basestring): # Except file-likes here
if os.path.isdir(destination):
destination = os.path.join(destination, self.filename)
if not overwrite and os.path.exists(destination):
raise IOError('File exists.')
with open(destination, 'wb') as fp:
self._copy_file(fp, chunk_size)
self._copy_file(fp, chunk_size, max_size)
else:
self._copy_file(destination, chunk_size)
self._copy_file(destination, chunk_size, max_size)

###############################################################################
# Application Helper ###########################################################
Expand Down