Files

View as Markdown

File content does not travel in ordinary object messages. You download it in blocks through a download session, and you upload it either inline in the request that creates the object (up to 10 MiB) or in blocks through an upload session. Files belong to object versions; see Objects and versions.

Which method to use

Task Use
Read a file of an object version DownloadFile_Begin, DownloadFile_ReadBlock in a loop, DownloadFile_Stop
Create a single-file document with a file of at most 10 MiB AddObjectWithFiles with the content inline (OBJ_FILE_SOURCE_TYPE_FILE_CONTENT)
Create a document with a file of any size UploadTempFile in blocks, UploadTempFileCommit, then AddObjectWithFiles with the upload ID (OBJ_FILE_SOURCE_TYPE_UPLOADED_FILE)

DownloadFile, DownloadFileWithDownloadID, DownloadFileWithDownloadKey, GetFileDownloadUrl and GetFileDownloadUrl2 of IRPCObjectOperations serve the mf-http-grpc gateway: over native gRPC they answer "Not implemented.". The stateless upload services are described at the end of this page. The download guide and the create-document guide show the calls in code.

Downloading

  1. Take the file's version from the object version: ObjectVersion.files[] gives each file's file_ver (file ID and file version), title, extension and size.
  2. Call DownloadFile_Begin with obj_file_ver (the object's obj_id and the file's file_ver), format (FILE_FORMAT_NATIVE for the file as stored), and prepare_file_for_downloading: true. Without that flag the server only checks access and records the access, and opens no download session. Set need_checksum: true to get the MD5 checksum in file_outline.md5_checksum. The response has download_id and file_outline with the size to expect.
  3. Call DownloadFile_ReadBlock with download_id, offset from 0 and block_size (request min(block size, size - offset) each time) until you have read file_outline.size bytes. Do not read again after the last byte: the server has closed the download session. block_size can be at most 4 MiB (4 194 304 bytes); a larger value fails with E_INVALIDARG ("Block size exceeded the limit of 4194304 bytes.").
  4. Call DownloadFile_Stop with the download_id.

Verified with a 3 MiB file in 4 MiB blocks: the downloaded bytes and the server's MD5 matched the upload.

Your receive limit. A 4 MiB block plus framing is just over the 4 MiB default receive limit of most gRPC libraries and fails on the client with RESOURCE_EXHAUSTED. Raise the limit, or read smaller blocks such as 1 MiB. See Connecting.

Download sessions.

Uploading inline

For small files, put the content in the creating request:

AddObjectWithFiles
  object_type_id: 0
  properties: [ class, name or title, ... ]
  check_in: true
  files: { type: OBJ_FILE_SOURCE_TYPE_FILE_CONTENT
           data.file_content: { title: "report", extension: "pdf", file_data: <bytes> } }

Inline content works only for a single-file document (object type 0 with property 22, Single file, true), needs a title, and is limited to 10 MiB (10 485 760 bytes); a larger file fails with E_INVALIDARG ("The parameter is incorrect. (Inline file content: fileSize exceeds the maximum allowed for inline content.)"), and so does inline content for a multi-file document. A 5 MiB file was created this way. Use an upload session for anything else.

Uploading in blocks (upload sessions)

  1. Call UploadTempFile with upload_id: 0, total_size_in_bytes, offset: 0 and the first block in data. Keep the returned upload_id.
  2. Send the next blocks with the same upload_id and their offset. Make every block except the last a multiple of 4096 bytes; 1 MiB blocks work well.
  3. Call UploadTempFileCommit with upload_id and logical_size (the file size). Leave low_digest and high_digest 0. If the commit fails, the upload is gone: upload the file again.
  4. Create the document with AddObjectWithFiles and files: { type: OBJ_FILE_SOURCE_TYPE_UPLOADED_FILE, data.uploaded_file: { upload_id, title, extension, size } }.

Verified with a 3 MiB file in 1 MiB blocks; the new document's file had the expected size and MD5.

Upload sessions.

Stateless uploads (switched off by default)

IRPCFileTransfer (FileUploadBegin, FileUploadEnd, FileUploadAttach) and the client-streaming IRPCFileTransferStreaming (FileUploadWhole, FileUploadBlock) upload without an upload session: the upload is identified by a file_ref. In M-Files Server 26.11 this feature is switched off by default: every method of the two services answers "Not implemented." (E_NOTIMPL), and the capability ServerVaultCapabilities.file_upload_stateless_supported is false. Upload with UploadTempFile and UploadTempFileCommit as described above, and use the stateless services only on a server that reports the capability.