Directories and Many Files

upload_directory(local_path, remote_path) and download_directory(remote_path, local_path) preserve relative paths and empty folders. upload_files() and download_files() instead accept (source, destination) pairs.

Each returns TransferResult with a FileOutcome per entry: paths and a status of "completed", "failed" (with error), "skipped" (with reason), "paused" or "cancelled". One file failure does not stop the other files. Check result.ok and result.failed rather than treating a returned job result as universal success.

Uploading a Directory

import files_sdk

try:
  with files_sdk.Client(api_key="YOUR_API_KEY") as client:
    result = client.file.upload_directory("photos", "backup/photos", max_files=8)
    for outcome in result.failed:
      print(outcome.local_path, outcome.error)
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)

Uploading a Directory

Each file uses upload_file(). mkdir_parents defaults on unless params overrides it; parameters apply to every file. Symlinks and special files are skipped and reported. A changed or replaced source file fails alone.

Discovery walks folders in name order as transfers run, rather than retaining the whole tree. POSIX systems open each folder from its parent without following links, so a replaced folder cannot redirect the walk outside the tree.

Downloading a Folder

Discovery lists remote folders a page at a time. Each file uses a staged download_file() replacement; missing local folders and empty remote folders are created.

Directory downloads refuse destination-file or folder links, leaving their targets unchanged. This differs from single-file downloads, which follow a supplied destination link. POSIX systems publish through opened folders to prevent replacement links redirecting files outside the tree. Invalid local names and two remote names colliding locally, such as Read.txt/read.txt on case-insensitive filesystems, fail for that file alone.

A subfolder listing failure is a separate outcome. Failure to list the requested root raises instead.

Downloading a Folder

import files_sdk

try:
  result = files_sdk.download_directory("reports/2026", "local-reports")
  print(len(result.completed), "files")
  for outcome in result.failed:
    print(outcome.remote_path, outcome.error)
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)

Limits and Progress

Setting or behaviorMeaning
Explicit max_filesCaps simultaneous files from 1 to 64.
Default file admissionNormally 4. Eligible scaled-policy upload jobs start with 6 and can prepare up to 128 files to feed their target; noneligible jobs settle at 4.
Adaptive upload max_concurrencyA shared part target per destination profile across the job's files, not a separate target per file. Serial files and caps of one still participate.
Adaptive qualified-S3 downloadsShare one range controller/target for that job. Other bound downloads keep their own target, default 4. Unbound files use one response.
Static filesIndependent per-file max_concurrency, or 4.
Shared limiterBounds resources fairly across jobs/clients but does not share learned targets between jobs.

Later files in a job use what earlier files learned; a new job or single transfer starts afresh. Files in the same job use the client's TransferLimiter, including requests outside the adaptive target.

A progress callback receives TransferJobProgress on the calling thread, at most four times a second: completed, failed and skipped files, discovered files/bytes and whether discovery finished, and bytes transferred.

Stopping and Resuming

cancel_token, request_timeout, deadline or closing the client stop the whole job, wait for its transfers and raise. The error's result holds outcomes so far. checkpoint and pause_token apply to the job as in Pausing and Resuming.

The checkpoint records the site, Workspace, source/destination pairs, completed entries and each unfinished transfer. Completed files are skipped as "completed before" only after verification:

FileVerification
UploadSame unchanged local source and the remote file that upload created, checked with Files.com.
DownloadSame local file and a Files.com-provided download identity confirmed with Files.com. Completed storage-bound and unbound files are downloaded again.

Changed source/destination pairs transfer again. Unfinished storage-bound files can reuse saved spans after confirming their version and private stage. Missing ranges resume only where storage honors Range; otherwise the verified version is fetched whole. An all-completed/skipped job removes its checkpoint; a job with failures keeps it so a later run can retry those entries.