Docs: reading and writing files; patch_inplace() is not atomic

- New page features/files.md: read a file with a stream and check that it
  was opened, serialize before opening the output file, replace a file via a
  temporary file and rename, binary formats in binary mode. The library keeps
  no file I/O of its own.
- patch_inplace(): say what a failed patch leaves behind (the earlier
  operations, and a failing move may already have removed its source) and
  point to patch() for all-or-nothing behaviour.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-11-02 20:39:45 +01:00
1 parent baba5db36f
commit 34ca0efc03
8 files changed
+150 -5

No files matched your search

@@ -15,7 +15,9 @@ the patch. This function applies a JSON patch in place and returns void.
## Exception safety
No guarantees, value may be corrupted by an unsuccessful patch operation.
No guarantees: if an operation fails, the operations before it stay applied, and a failing `move` operation may already
have removed the value at its "from" location. Use [`patch`](patch.md) if the value must be unchanged after a failed
patch.
## Exceptions
@@ -62,8 +64,19 @@ the JSON value, the complexity can usually be neglected.
## Notes
Unlike [`patch`](patch.md), `patch_inplace` applies the operation "in place" and no copy of the JSON value is created.
That makes it faster for large documents by avoiding the copy. However, the JSON value might be corrupted if the
function throws an exception.
That makes it faster for large documents by avoiding the copy.
!!! warning "Not atomic"
`patch_inplace` applies the operations one after the other and does not undo them when one fails. After an
exception, the value holds the result of the operations before the failing one, and a failing `move` operation
(a "remove" followed by an "add") may already have removed the value at its "from" location; see the second example
below. [RFC 6902](https://tools.ietf.org/html/rfc6902#section-5) requires that a patch with a failing operation is
not deemed successful, but leaves open what happens to the document.
If the value must stay unchanged when the patch fails, use [`patch`](patch.md), which applies the patch to a copy:
`#!cpp j = j.patch(json_patch);`. Validating the patch beforehand is not enough, as "test" operations and missing
paths are only detected while the patch is applied.
Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last one
is kept, see [`object_t`](object_t.md#behavior)), so `#!json {"op": "add", "op": "remove", "path": "/a"}` is a