document_stream()

Reads a byte range from a document file via std.GetDocumentStream. The server reads length bytes starting at offset from the page-th file of the document and returns them as the contents of a single response file, which is converted to bytes and returned to the caller.

This method is well suited to streaming large files in chunks without having to download a full copy via files().

offset and length are not capped at 2 GiB: the job transports both as decimal text, and reads beyond the 2 GiB mark of a file work (verified against a live server). Negative values raise a ValueError client-side.

Each call reopens the source file server-side, so do not issue overlapping document_stream() calls against the same document from several connections at once — the server may otherwise fail with a Windows file-sharing violation (CreateFile … "used by another process"). Read a single document serially, or use files_streaming() for true streaming without local buffering.

1. Signature

  • Sync

  • Async

ecm.dms.document_stream(
    model: ECMDocumentModel | int,
    object_type_id: int | None = None,
    *,
    offset: int = 0,
    length: int,
    page: int = 1,
) -> bytes
await ecm.dms.document_stream(
    model: ECMDocumentModel | int,
    object_type_id: int | None = None,
    *,
    offset: int = 0,
    length: int,
    page: int = 1,
) -> bytes

2. Parameters

Parameter Type Default Description

model

ECMDocumentModel | int

The document: either an ECMDocumentModel instance (its system.id is used) or a plain integer object ID.

object_type_id

int | None

None

Numeric object type ID. Resolved automatically when None — taken from the model when available, or fetched via get_object_type_by_id() for plain IDs.

offset

int

0

Zero-based byte offset at which to start reading. Must be non-negative and less than the file size; otherwise the server returns ERR_WRONGPARAM. No 2 GiB limit; negative → ValueError.

length

int

Number of bytes to read. The server may return fewer bytes if the requested range extends past the end of the file. Must be non-negative (no 2 GiB limit); negative → ValueError.

page

int

1

One-based page index of the document file to read from (default 1).

3. Return value

The requested byte range as a single bytes object. May be shorter than length if the file ends earlier. Returns an empty bytes object when the server produces no file.

4. Possible server error codes

The server may raise these errors (as ECMException):

  • ERR_WRONGPARAM — offset is greater than the file size.

  • ERR_GETOBJECTDEFPARAM — unknown object type.

  • ERR_GETPARAMETER — not enough (valid) parameters supplied.

  • ERR_SQLSELECT — DB query error.

  • ERR_NOTDEFINED_YET — object lives on a remote server.

  • ERR_INSOURCE — source file cannot be found or opened.

  • ERR_INDESTINATION — destination file cannot be created.

5. Examples

5.1. Read the first 50 bytes

  • Sync

  • Async

header = ecm.dms.document_stream(doc, offset=0, length=50)
print(header[:4])  # e.g. file-magic check
header = await ecm.dms.document_stream(doc, offset=0, length=50)

5.2. Stream a file in chunks

  • Sync

  • Async

chunks = []
pos = 0
chunk_size = 64 * 1024  # 64 KiB
while True:
    chunk = ecm.dms.document_stream(doc, offset=pos, length=chunk_size)
    if not chunk:
        break
    chunks.append(chunk)
    pos += len(chunk)
    if len(chunk) < chunk_size:
        break  # End-of-file reached
full_content = b"".join(chunks)
chunks = []
pos = 0
chunk_size = 64 * 1024
while True:
    chunk = await ecm.dms.document_stream(doc, offset=pos, length=chunk_size)
    if not chunk:
        break
    chunks.append(chunk)
    pos += len(chunk)
    if len(chunk) < chunk_size:
        break
full_content = b"".join(chunks)

5.3. By plain integer ID without type resolution

When the object type ID is already known, pass it explicitly to skip the extra get_object_type_by_id() round trip:

obj_type = ecm.dms.get_object_type_by_id(doc_id)
chunk = ecm.dms.document_stream(doc_id, obj_type, offset=0, length=1024)

6. Comparison with files()

Aspect files() document_stream()

Result type

List of JobResponseFile

bytes

Transfer

Whole file(s) at once

Configurable byte range

Multiple files

Yes (one per page)

No — single page per call

Streaming friendly

Limited

Excellent — enables chunking

Server job

std.StoreInCacheById

std.GetDocumentStream

Max. file size

Unlimited

Unlimited (serial; no int32 limit on offset/length)

To stream a whole file without local buffering — or when concurrent access is required — files_streaming() is the right choice: it reads the file chunk-by-chunk straight off the connection and opens the source file only once.

7. See also

  • files() — Download the full files of a document

  • files_streaming() — Stream files chunk-by-chunk without local buffering

  • digest() — Retrieve the hash of a document