Downloads

download_file() saves a remote file to a local path; download_stream() writes it into a binary stream. Both return the downloaded File.

The SDK fetches parallel ranges where storage supports them with reliable version checks, and adjusts concurrency on eligible storage. It can fall back to a whole response when needed. Start with the paths; no tuning is required. Temporary failures are retried within a limit, and you can follow the transfer with a progress callback.

cancel_token, request_timeout and deadline cover the operation from obtaining its download URL to the last byte. See Cancellation and Deadlines.

Downloading a File

import files_sdk

try:
  with files_sdk.Client(api_key="YOUR_API_KEY") as client:
    file = client.file.download_file("archive/big.iso", "downloads/big.iso")
    print(file.path, file.size)
except files_sdk.error.NotAuthenticatedError as err:
  print(f"Authentication Error Occurred ({type(err).__name__}):", err)
except files_sdk.error.Error as err:
  print(f"Unknown Error Occurred ({type(err).__name__}):", err)

Local Files

download_file() writes to a private temporary file beside the destination, then puts it in place after the full response is validated. It replaces an existing destination. If the destination is a symbolic link, a single-file download replaces the file it points to; directory downloads instead refuse links. Other hard links to a replaced file keep the old content.

A failure or cancellation before publication leaves the destination unchanged. With a checkpoint, a complete, version-bound private stage can sometimes be kept for recovery; see Pausing and Resuming. A partial whole response starts from the beginning on the next call.

Without local_path, the file is saved under its own name in the current directory. The SDK needs permission to create a temporary directory beside the destination. Local Access and Publication describes platform access rules and failures that prevent replacement.

Streams

download_stream(path, stream) writes from the stream's current position, in order, and leaves it open. It never seeks, truncates or rewinds. A failure can leave partial content in the stream, and already-written bytes are never written again. Whole-response retries stop once the stream has accepted bytes.

The stream must be blocking. Partial writes are completed before proceeding. A raw stream returning None or 0 from write() raises InvalidParameterError; for other writers, None means all bytes were accepted. Cancellation stops before the next write, and your stream's exceptions propagate unchanged.

Ranges fetched ahead are buffered within the client's shared TransferLimiter. For a remote file downloaded as you read it, use files_sdk.open(path, "r") or "rb"; text uses UTF-8. See Remote Files and Folders.

Downloading Into a Stream

import files_sdk

try:
  with open("report.csv", "ab") as output:
    files_sdk.download_stream("reports/report.csv", output)
except files_sdk.error.NotAuthenticatedError as err:
  print(f"Authentication Error Occurred ({type(err).__name__}):", err)
except files_sdk.error.Error as err:
  print(f"Unknown Error Occurred ({type(err).__name__}):", err)

This example appends to the local file. Choose its open mode deliberately; use download_file() for staged replacement.

Progress

Pass a function as progress. It receives files_sdk.DownloadProgress on the calling thread, at most four times a second while bytes arrive, and once more at completion. If it raises, active ranges stop and its exception is propagated. Mark the operation successful only after the download call returns.

FieldMeaning
bytes_committedComplete range bytes, or bytes accepted by the stream. For whole responses, written bytes reset to zero if the response restarts.
bytes_receivedNetwork bytes, including retries.
total_bytesSize from the bound version or response length. For an encoded whole response, the size is known only at the end.
pinned_versionWhether the download is protected by one verified version, independently of whether it uses ranges or a whole response.

Following Download Progress

def report(progress):
  print(f"{progress.bytes_committed} of {progress.total_bytes} bytes")

file = files_sdk.download_file("reports/report.csv", "report.csv", progress=report)

Failures

Temporary range failures, short responses and overruns are retried as Retries and Timeouts describes. An overrun fails before excess bytes are written. A failed whole response restarts from byte zero only while the destination can restart; a stream that has taken bytes cannot.

SituationOutcome
Storage URL expired or expires within a minuteRenewed for the same version, up to twice. Other refusals, including an ordinary 403, fail.
Version is gone or changed, including storage HTTP 412 or a changed bound storage tagA local-file download starts over once with the current version. A stream already holding old-version bytes raises InvalidRequestError.
Invalid identity, malformed or encoded range, disallowed redirect, missing required bound storage tag, or web-app responseAPIConnectionError before bytes from that invalid response are written.
Storage ignores a rangeAPI-identity downloads reject it; qualified storage-bound downloads may fetch the same version whole, as below.

URLs are used exactly as Files.com supplies them. Expiry checks recognize the supplied expiry and supported signed-URL fields for AWS, Files.com, Google and Azure. Source and destination stream exceptions retain their own type.

Ranges at Once

Version-bound downloads use 8 MiB ranges. Eligible Amazon S3 downloads use the scaled policy: an initial target of 150 ranges, adapting to throughput, failures, throttling and queueing. Downloads have no upload startup choice or warmup. Other storage with a Files.com-provided identity fetches 4 ranges by default. An endpoint's name selects tuning; it does not by itself establish a version.

max_concurrency, from 1 to 1024, caps the target. tuning accepts files_sdk.UploadTuning; UploadTuning(adaptive=False) keeps max_concurrency ranges (or 4) at once. Custom concurrency settings use the configurable controller. Upload-only settings such as startup, observer and part-size options are refused.

Each range reserves buffer space first: a 256 KiB copy buffer for a local file, or the whole range for an ordered stream. Each network attempt holds a controller place and limiter max_parts slot only while active. Retry and URL-renewal waits release both slots, keep reserved memory, and wait behind cooldowns. HTTP 429, 503 or 504 pauses new ranges for Retry-After, even if reading the error body fails. Measurements exclude local-file write time.

Adaptive files within download_directory() or download_files() share a controller for that job; nonadaptive downloads keep independent targets.

Download Identity

Version protection is automatic. There are two supported sources:

SourceBinding and checks
Files.com-provided download identitywith_download_identity supplies a token, exact size and required headers. Each range must match the requested bytes and size. Required If-Match tags must match any returned strong ETag; a missing response tag remains accepted for compatibility. Renewal with expected_download_identity must return the same token and size.
Qualified storage responseWithout API identity, HTTPS Amazon S3 general-purpose endpoints on the default port can bind from a first valid HTTP 206 range at byte zero: exact unencoded bytes, authoritative size and a strong ETag. Later requests use If-Match, validate every range/size/tag and follow no redirect. Renewed URLs must name the same storage object.

API-identity requests can follow redirects within their original origin, retaining required headers. Cross-origin redirects fail before sending there. Storage-bound requests follow no redirects. The storage binding's tag, size and address digest are an SDK record and are never sent to Files.com. This is a qualified conditional-range protocol, not a guess from equal ETags, sizes or modification times.

Other storage uses one unbound response. On eligible storage, an initial HTTP 200, 416 or redirect also falls back to a whole response. A valid first range without a strong tag stays unbound: it can serve as the whole response if it already contains the entire small file; otherwise the SDK fetches the file whole. Malformed initial range encoding, byte coverage or length raises APIConnectionError instead of falling back. Unbound downloads keep no reusable checkpoint. After storage binding, a missing tag fails validation and a weak or different tag indicates a changed version, handled as described under Failures.

If qualified storage starts ignoring ranges after binding, the SDK stops other ranges, discards their partial writes and fetches the whole same version with If-Match. pinned_version remains true. A stream that already accepted bytes fails instead. A partial whole response restarts; it is not continued mid-response. A complete bound private local stage may be reused only after checkpoint sync/save and the same identity, privacy, exact-size and version checks; see Pausing and Resuming.

An identity grants no permissions and is not logged at INFO or above. Checkpoints contain the token/size, or the storage tag/size/resource digest, never credentials, headers or signed URLs. Recovery confirms the version before reusing bytes; missing ranges are fetched only where storage still honors Range.

Local Access and Publication

The temporary directory is named .files_sdk- plus 32 hexadecimal digits. Its directory and file are owner-only; on macOS inherited ACLs are removed before writing. On POSIX systems, operations use the opened destination directory's descriptors, protecting against other users and links replaced during the download, but not programs running as you. Windows uses paths without that protection.

The replacement keeps existing file permissions without set-user-ID, set-group-ID or sticky bits. POSIX systems also preserve its owner and group; macOS/Linux preserve its ACL. Inability to keep that access raises files_sdk.localfs.AccessNotKept, an OSError, instead of replacing the file. New macOS files receive their parent folder's inherited ACL at publication; inability to apply it also fails. Windows does not retain a replaced file's own access-control entries. The destination directory's permissions are unchanged.