'Retrieves a file from a Key
:type key: :class:`boto.s3.key.Key` or subclass
:param key: The Key object from which upload is to be downloaded
:type fp: file
:param fp: File pointer into which data should be downloaded
:type headers: string
:param: headers to send when retrieving the files
:type cb: function
:param cb: (optional) a callback function that will be called to report
progress on the download.  The callback should accept two integer
parameters, the first representing the number of bytes that have
been successfully transmitted from the storage service and
the second representing the total number of bytes that need
to be transmitted.
:type num_cb: int
:param num_cb: (optional) If a callback is specified with the cb
parameter this parameter determines the granularity of the callback
by defining the maximum number of times the callback will be
called during the file transfer.
:type torrent: bool
:param torrent: Flag for whether to get a torrent for the file
:type version_id: string
:param version_id: The version ID (optional)
:type hash_algs: dictionary
:param hash_algs: (optional) Dictionary of hash algorithms and
corresponding hashing class that implements update() and digest().
Defaults to {\'md5\': hashlib/md5.md5}.
Raises ResumableDownloadException if a problem occurs during
the transfer.'

def get_file(self, key, fp, headers, cb=None, num_cb=10, torrent=False, version_id=None, hash_algs=None):

    debug = key.bucket.connection.debug
    if (not headers):
        headers = {}
    if (self.num_retries is None):
        self.num_retries = config.getint('Boto', 'num_retries', 6)
    progress_less_iterations = 0
    while True:
        had_file_bytes_before_attempt = get_cur_file_size(fp)
        try:
            self._attempt_resumable_download(key, fp, headers, cb, num_cb, torrent, version_id, hash_algs)
            self._remove_tracker_file()
            if (debug >= 1):
                print 'Resumable    download    complete.'
            return
        except self.RETRYABLE_EXCEPTIONS as e:
            if (debug >= 1):
                print ('Caught    exception    (%s)' % e.__repr__())
            if (isinstance(e, IOError) and (e.errno == errno.EPIPE)):
                if isinstance(key, GSKey):
                    key.get_file(fp, headers, cb, num_cb, torrent, version_id, override_num_retries=0, hash_algs=hash_algs)
                else:
                    key.get_file(fp, headers, cb, num_cb, torrent, version_id, override_num_retries=0)
        except ResumableDownloadException as e:
            if (e.disposition == ResumableTransferDisposition.ABORT_CUR_PROCESS):
                if (debug >= 1):
                    print ('Caught    non-retryable    ResumableDownloadException    (%s)' % e.message)
                raise
            elif (e.disposition == ResumableTransferDisposition.ABORT):
                if (debug >= 1):
                    print ('Caught    non-retryable    ResumableDownloadException    (%s);    aborting    and    removing    tracker    file' % e.message)
                self._remove_tracker_file()
                raise
            elif (debug >= 1):
                print ('Caught    ResumableDownloadException    (%s)    -    will    retry' % e.message)
        if (get_cur_file_size(fp) > had_file_bytes_before_attempt):
            progress_less_iterations = 0
        else:
            progress_less_iterations += 1
        if (progress_less_iterations > self.num_retries):
            raise ResumableDownloadException('Too    many    resumable    download    attempts    failed    without    progress.    You    might    try    this    download    again    later', ResumableTransferDisposition.ABORT_CUR_PROCESS)
        try:
            key.close()
        except httplib.IncompleteRead:
            pass
        sleep_time_secs = (2 ** progress_less_iterations)
        if (debug >= 1):
            print ('Got    retryable    failure    (%d    progress-less    in    a    row).\nSleeping    %d    seconds    before    re-trying' % (progress_less_iterations, sleep_time_secs))
        time.sleep(sleep_time_secs)
