@@ -216,19 +216,68 @@ def delete(self):
216216 """
217217 return self .bucket .delete_blob (self )
218218
219- def download_to_file (self , file_obj ):
219+ def download (self , filename_or_buffer = None ):
220+ """Download the contents of this blob.
221+
222+ Supports downloading
223+ - directly as string (via a temporary buffer)
224+ - into a file on the local filesystem
225+ - into an existing buffer (possibly to a file)
226+
227+ If called with no arguments, returns a string::
228+
229+ >>> print blob.download()
230+ 'contents-of-blob'
231+
232+ :type filename_or_buffer: string, writable buffer or ``NoneType``
233+ :param filename_or_buffer: An optional filename or a writable buffer
234+ to download contents into.
235+
236+ :raises: :class:`gcloud.exceptions.NotFound`
237+ :rtype: string or ``NoneType``
238+ :returns: The downloaded file if ``filename_or_buffer`` is ``None``.
239+ """
240+ return_string = update_mtime = False
241+
242+ if filename_or_buffer is None :
243+ buffer_obj = BytesIO ()
244+ return_string = True
245+ elif isinstance (filename_or_buffer , six .string_types ):
246+ buffer_obj = open (filename_or_buffer , 'wb' )
247+ update_mtime = True
248+ else :
249+ buffer_obj = filename_or_buffer
250+
251+ try :
252+ self ._download_to_buffer (buffer_obj )
253+
254+ if return_string :
255+ return buffer_obj .getvalue ()
256+ finally :
257+ if update_mtime :
258+ buffer_obj .close ()
259+
260+ mtime = time .mktime (
261+ datetime .datetime .strptime (
262+ self .properties ['updated' ],
263+ '%Y-%m-%dT%H:%M:%S.%fz' ).timetuple ()
264+ )
265+ os .utime (buffer_obj .name , (mtime , mtime ))
266+
267+ def _download_to_buffer (self , buffer_obj ):
220268 """Download the contents of this blob into a file-like object.
221269
222- :type file_obj: file
223- :param file_obj : A file handle to which to write the blob's data .
270+ :type buffer_obj: writable object
271+ :param buffer_obj : A buffer object with a write() method .
224272
225273 :raises: :class:`gcloud.exceptions.NotFound`
226274 """
227275
228276 download_url = self .media_link
229277
230278 # Use apitools 'Download' facility.
231- download = transfer .Download .FromStream (file_obj , auto_transfer = False )
279+ download = transfer .Download .FromStream (buffer_obj ,
280+ auto_transfer = False )
232281 download .chunksize = self .CHUNK_SIZE
233282 headers = {'Range' : 'bytes=0-%d' % (self .CHUNK_SIZE - 1 )}
234283 request = http_wrapper .Request (download_url , 'GET' , headers )
@@ -241,6 +290,16 @@ def download_to_file(self, file_obj):
241290 download .StreamInChunks (callback = lambda * args : None ,
242291 finish_callback = lambda * args : None )
243292
293+ def download_to_file (self , file_obj ):
294+ """Download the contents of this blob into a file-like object.
295+
296+ :type file_obj: file
297+ :param file_obj: A file handle to which to write the blob's data.
298+
299+ :raises: :class:`gcloud.exceptions.NotFound`
300+ """
301+ self .download (file_obj )
302+
244303 def download_to_filename (self , filename ):
245304 """Download the contents of this blob into a named file.
246305
@@ -249,15 +308,7 @@ def download_to_filename(self, filename):
249308
250309 :raises: :class:`gcloud.exceptions.NotFound`
251310 """
252- with open (filename , 'wb' ) as file_obj :
253- self .download_to_file (file_obj )
254-
255- mtime = time .mktime (
256- datetime .datetime .strptime (
257- self .properties ['updated' ],
258- '%Y-%m-%dT%H:%M:%S.%fz' ).timetuple ()
259- )
260- os .utime (file_obj .name , (mtime , mtime ))
311+ self .download (filename )
261312
262313 def download_as_string (self ):
263314 """Download the contents of this blob as a string.
@@ -266,9 +317,7 @@ def download_as_string(self):
266317 :returns: The data stored in this blob.
267318 :raises: :class:`gcloud.exceptions.NotFound`
268319 """
269- string_buffer = BytesIO ()
270- self .download_to_file (string_buffer )
271- return string_buffer .getvalue ()
320+ return self .download ()
272321
273322 def upload_from_file (self , file_obj , rewind = False , size = None ,
274323 content_type = None , num_retries = 6 ):
0 commit comments