This commit is contained in:
nlohmann committed 2026-11-07 09:32:17 +00:00
1 parent 5531ec9380
commit cf8df97ba7
12 files changed
+440 -428

No files matched your search

+14 -4
View File
@@ -5,7 +5,9 @@
```
When defined to `1`, parsing from a `#!cpp FILE*` reads every character with `std::fgetc`, as in version 3.12.0 and
earlier, instead of locking the file once and reading it with the unlocked stdio functions.
earlier, instead of locking the file once and reading it with the unlocked stdio functions. This also turns off the
scan of the `FILE`'s buffer in bulk (see below), which [`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)
does not affect.
It does not change any result: values, exceptions, and the position of the file after parsing are the same either way.
Only the speed and the locking of the file differ (see the notes on locking below).
@@ -37,9 +39,17 @@ The default value is `0`: the file is locked once and read with the unlocked std
| Microsoft (MSVC, clang-cl) | `_lock_file`, `_fgetc_nolock`, `_unlock_file` |
| others (e.g., musl, MinGW, newlib) | `std::fgetc`, as before |
This makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with
glibc, whose locking is cheaper. The binary formats ([`from_cbor`](../basic_json/from_cbor.md),
[`from_msgpack`](../basic_json/from_msgpack.md), ...) read from a `FILE*` the same way.
With glibc and the Apple C library, the parser also scans the characters that the `FILE` already holds in its
buffer in bulk, as it scans the get area of a stream (see
[`JSON_DISABLE_STREAM_BULK_SCAN`](json_disable_stream_bulk_scan.md)): it reads the same fields of the `FILE` that
the C library's own `getc_unlocked` reads, and it consumes exactly the characters that `getc_unlocked` would have
returned, so the file is left where it was left before.
Locking the file once makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3
times as fast with glibc, whose locking is cheaper. Scanning the buffer in bulk makes `parse()` another 1.7 to 2.6
times as fast (and `accept()` 2.9 to 4.4 times), about as fast as parsing from a `std::ifstream`. The binary
formats ([`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md), ...) read
from a `FILE*` the same way.
!!! note "Locking"
@@ -1,6 +1,6 @@
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="JSON for Modern C++ is a header-only C++11 library that makes JSON a first-class data type."><meta name=author content="Niels Lohmann"><link href="https://json.nlohmann.me/api/macros/json_disable_unlocked_file_io/" rel="canonical"><link href=../json_disable_tuple_reference_conversion/ rel=prev><link href=../json_has_cpp_11/ rel=next><link rel=icon href=../../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.8.0"><title>JSON_DISABLE_UNLOCKED_FILE_IO - JSON for Modern C++</title><link rel=stylesheet href=../../../assets/stylesheets/main.57a0d79d.min.css><link rel=stylesheet href=../../../assets/stylesheets/palette.fb2fffe2.min.css><link rel=stylesheet href=../../../css/custom.css><link rel=stylesheet href=../../../css/brand.css><link rel=stylesheet href=../../../css/fig-sax.css><link rel=stylesheet href=../../../css/fig-jsonview.css><link rel=stylesheet href=../../../css/fig-exceptions.css><link rel=stylesheet href=../../../css/fig-pointer.css><link rel=stylesheet href=../../../css/fig-charts.css><link rel=stylesheet href=../../../css/fig-integration.css><link rel=stylesheet href=../../../css/fig-macros.css><script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=custom data-md-color-accent=custom> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#json_disable_unlocked_file_io class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../../.. title="JSON for Modern C++" class="md-header__button md-logo" aria-label="JSON for Modern C++" data-md-component=logo> <img src=../../../images/wordmark-header.svg alt=logo> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> JSON for Modern C++ </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> JSON_DISABLE_UNLOCKED_FILE_IO </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme=default data-md-color-primary=custom data-md-color-accent=custom aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme=slate data-md-color-primary=custom data-md-color-accent=custom aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icoLine truncated
</code></pre></div> <p>When defined to <code>1</code>, parsing from a <code class=highlight><span class=kt>FILE</span><span class=o>*</span></code> reads every character with <code>std::fgetc</code>, as in version 3.12.0 and earlier, instead of locking the file once and reading it with the unlocked stdio functions.</p> <p>It does not change any result: values, exceptions, and the position of the file after parsing are the same either way. Only the speed and the locking of the file differ (see the notes on locking below).</p> <p>Builds with MemorySanitizer use <code>std::fgetc</code> automatically, because the inline <code>getc_unlocked</code> of glibc reads the stdio buffer directly, which glibc (not instrumented) filled, and MemorySanitizer would report it as uninitialized.</p> <h2 id=default-definition>Default definition<a class=headerlink href=#default-definition title="Permanent link">&para;</a></h2> <p>The default value is <code>0</code>: the file is locked once and read with the unlocked stdio functions where they are available.</p> <div class=highlight><pre><span></span><code><span class=cp>#define JSON_DISABLE_UNLOCKED_FILE_IO 0</span>
</code></pre></div> <h2 id=notes>Notes<a class=headerlink href=#notes title="Permanent link">&para;</a></h2> <div class="admonition note"> <p class=admonition-title>Background</p> <p>The C standard library makes every <code>std::fgetc</code> call thread-safe by locking and unlocking the <code>FILE</code> object. When parsing from a <code>FILE*</code>, the parser reads one character at a time, so this happens for every character of the input.</p> <p>Instead, the parser locks the file once when parsing starts and unlocks it when parsing ends - also when an exception is thrown - and reads the characters in between without locking:</p> <table> <thead> <tr> <th>C library</th> <th>functions</th> </tr> </thead> <tbody> <tr> <td>glibc (Linux), Apple (macOS, iOS), Android, FreeBSD, NetBSD, OpenBSD, DragonFly BSD</td> <td><code>flockfile</code>, <code>getc_unlocked</code>, <code>funlockfile</code> (POSIX)</td> </tr> <tr> <td>Microsoft (<abbr title="Microsoft Visual C++">MSVC</abbr>, clang-cl)</td> <td><code>_lock_file</code>, <code>_fgetc_nolock</code>, <code>_unlock_file</code></td> </tr> <tr> <td>others (e.g., musl, <abbr title="Minimalist GNU for Windows">MinGW</abbr>, newlib)</td> <td><code>std::fgetc</code>, as before</td> </tr> </tbody> </table> <p>This makes parsing from a <code>FILE*</code> 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with glibc, whose locking is cheaper. The binary formats (<a href=../../basic_json/from_cbor/ ><code>from_cbor</code></a>, <a href=../../basic_json/from_msgpack/ ><code>from_msgpack</code></a>, ...) read from a <code>FILE*</code> the same way.</p> </div> <div class="admonition note"> <p class=admonition-title>Locking</p> <p>While a value is parsed from a <code>FILE*</code>, the parsing thread holds the file's lock. The lock is recursive, so the parsing thread itself - for instance, a <a href=../../json_sax/ ><abbr title="Simple API for XML">SAX</abbr></a> handler or a <a href=../../basic_json/parser_callback_t/ >parser callback</a> - can keep using the file with stdio functions such as <code>std::ftell</code>. Other threads that use the same <code>FILE</code> object wait until the parser is done. Before, they could interleave their reads with the parser's, which made the parsed input unpredictable anyway.</p> <p>A program in which a <abbr title="Simple API for XML">SAX</abbr> handler or parser callback waits for <strong>another</strong> thread that uses the <strong>same</strong> <code>FILE</code> object would deadlock. Define the macro to <code>1</code> for such programs.</p> </div> <div class="admonition note"> <p class=admonition-title><abbr title="Application Binary Interface">ABI</abbr> compatibility</p> <p>The value of this macro is encoded in the <a href=../../../features/namespace/ >namespace</a> (tag <code>_dufio</code>), resulting in distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program without One Definition Rule (<abbr title="One Definition Rule">ODR</abbr>) violations, but they cannot exchange instances of library types.</p> </div> <div class="admonition note"> <p class=admonition-title>Other inputs</p> <p>Reading from a <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>istream</span></code> is not affected by this macro; see <a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> for that input.</p> </div> <h2 id=examples>Examples<a class=headerlink href=#examples title="Permanent link">&para;</a></h2> <details class=example> <summary>Example: parsing from a <code>FILE*</code> (default)</summary> <p>The file is locked once while it is parsed:</p> <div class=highlight><pre><span></span><code><span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;cstdio&gt;</span>
</code></pre></div> <p>When defined to <code>1</code>, parsing from a <code class=highlight><span class=kt>FILE</span><span class=o>*</span></code> reads every character with <code>std::fgetc</code>, as in version 3.12.0 and earlier, instead of locking the file once and reading it with the unlocked stdio functions. This also turns off the scan of the <code>FILE</code>'s buffer in bulk (see below), which <a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> does not affect.</p> <p>It does not change any result: values, exceptions, and the position of the file after parsing are the same either way. Only the speed and the locking of the file differ (see the notes on locking below).</p> <p>Builds with MemorySanitizer use <code>std::fgetc</code> automatically, because the inline <code>getc_unlocked</code> of glibc reads the stdio buffer directly, which glibc (not instrumented) filled, and MemorySanitizer would report it as uninitialized.</p> <h2 id=default-definition>Default definition<a class=headerlink href=#default-definition title="Permanent link">&para;</a></h2> <p>The default value is <code>0</code>: the file is locked once and read with the unlocked stdio functions where they are available.</p> <div class=highlight><pre><span></span><code><span class=cp>#define JSON_DISABLE_UNLOCKED_FILE_IO 0</span>
</code></pre></div> <h2 id=notes>Notes<a class=headerlink href=#notes title="Permanent link">&para;</a></h2> <div class="admonition note"> <p class=admonition-title>Background</p> <p>The C standard library makes every <code>std::fgetc</code> call thread-safe by locking and unlocking the <code>FILE</code> object. When parsing from a <code>FILE*</code>, the parser reads one character at a time, so this happens for every character of the input.</p> <p>Instead, the parser locks the file once when parsing starts and unlocks it when parsing ends - also when an exception is thrown - and reads the characters in between without locking:</p> <table> <thead> <tr> <th>C library</th> <th>functions</th> </tr> </thead> <tbody> <tr> <td>glibc (Linux), Apple (macOS, iOS), Android, FreeBSD, NetBSD, OpenBSD, DragonFly BSD</td> <td><code>flockfile</code>, <code>getc_unlocked</code>, <code>funlockfile</code> (POSIX)</td> </tr> <tr> <td>Microsoft (<abbr title="Microsoft Visual C++">MSVC</abbr>, clang-cl)</td> <td><code>_lock_file</code>, <code>_fgetc_nolock</code>, <code>_unlock_file</code></td> </tr> <tr> <td>others (e.g., musl, <abbr title="Minimalist GNU for Windows">MinGW</abbr>, newlib)</td> <td><code>std::fgetc</code>, as before</td> </tr> </tbody> </table> <p>With glibc and the Apple C library, the parser also scans the characters that the <code>FILE</code> already holds in its buffer in bulk, as it scans the get area of a stream (see <a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a>): it reads the same fields of the <code>FILE</code> that the C library's own <code>getc_unlocked</code> reads, and it consumes exactly the characters that <code>getc_unlocked</code> would have returned, so the file is left where it was left before.</p> <p>Locking the file once makes parsing from a <code>FILE*</code> 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with glibc, whose locking is cheaper. Scanning the buffer in bulk makes <code>parse()</code> another 1.7 to 2.6 times as fast (and <code>accept()</code> 2.9 to 4.4 times), about as fast as parsing from a <code>std::ifstream</code>. The binary formats (<a href=../../basic_json/from_cbor/ ><code>from_cbor</code></a>, <a href=../../basic_json/from_msgpack/ ><code>from_msgpack</code></a>, ...) read from a <code>FILE*</code> the same way.</p> </div> <div class="admonition note"> <p class=admonition-title>Locking</p> <p>While a value is parsed from a <code>FILE*</code>, the parsing thread holds the file's lock. The lock is recursive, so the parsing thread itself - for instance, a <a href=../../json_sax/ ><abbr title="Simple API for XML">SAX</abbr></a> handler or a <a href=../../basic_json/parser_callback_t/ >parser callback</a> - can keep using the file with stdio functions such as <code>std::ftell</code>. Other threads that use the same <code>FILE</code> object wait until the parser is done. Before, they could interleave their reads with the parser's, which made the parsed input unpredictable anyway.</p> <p>A program in which a <abbr title="Simple API for XML">SAX</abbr> handler or parser callback waits for <strong>another</strong> thread that uses the <strong>same</strong> <code>FILE</code> object would deadlock. Define the macro to <code>1</code> for such programs.</p> </div> <div class="admonition note"> <p class=admonition-title><abbr title="Application Binary Interface">ABI</abbr> compatibility</p> <p>The value of this macro is encoded in the <a href=../../../features/namespace/ >namespace</a> (tag <code>_dufio</code>), resulting in distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program without One Definition Rule (<abbr title="One Definition Rule">ODR</abbr>) violations, but they cannot exchange instances of library types.</p> </div> <div class="admonition note"> <p class=admonition-title>Other inputs</p> <p>Reading from a <code class=highlight><span class=n>std</span><span class=o>::</span><span class=n>istream</span></code> is not affected by this macro; see <a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> for that input.</p> </div> <h2 id=examples>Examples<a class=headerlink href=#examples title="Permanent link">&para;</a></h2> <details class=example> <summary>Example: parsing from a <code>FILE*</code> (default)</summary> <p>The file is locked once while it is parsed:</p> <div class=highlight><pre><span></span><code><span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;cstdio&gt;</span>
<span class=cp>#include</span><span class=w> </span><span class=cpf>&lt;nlohmann/json.hpp&gt;</span>
<span class=k>using</span><span class=w> </span><span class=n>nlohmann</span><span class=o>::</span><span class=n>json</span><span class=p>;</span>
@@ -23,4 +23,4 @@
<span class=w> </span><span class=n>json</span><span class=w> </span><span class=n>j</span><span class=w> </span><span class=o>=</span><span class=w> </span><span class=n>json</span><span class=o>::</span><span class=n>parse</span><span class=p>(</span><span class=n>f</span><span class=p>);</span><span class=w> </span><span class=c1>// std::fgetc for every character</span>
<span class=w> </span><span class=n>std</span><span class=o>::</span><span class=n>fclose</span><span class=p>(</span><span class=n>f</span><span class=p>);</span>
<span class=p>}</span>
</code></pre></div> </details> <h2 id=see-also>See also<a class=headerlink href=#see-also title="Permanent link">&para;</a></h2> <ul> <li><a href=../../basic_json/parse/ ><code>parse</code></a> - deserialize from a compatible input</li> <li><a href=../../basic_json/sax_parse/ ><code>sax_parse</code></a> - generate <abbr title="Simple API for XML">SAX</abbr> events</li> <li><a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> - read a <code>std::istream</code> one character at a time</li> <li><a href=../../../features/parsing/#input-sources-and-performance>Parsing: input sources and performance</a> - how input sources affect parsing performance</li> <li><a href=../../../features/parsing/large_and_partial_input/ >Large, Streamed, and Partial Input</a> - chunked, concatenated, and very large input</li> </ul> <h2 id=version-history>Version history<a class=headerlink href=#version-history title="Permanent link">&para;</a></h2> <ul> <li>Added in version 3.13.0 <span class=unreleased-version title="Not part of a release yet; the latest release is 3.12.0.">unreleased</span>.</li> </ul> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date" title="October 27, 2026 06:41:42 UTC">October 27, 2026</span> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <nav class="md-footer__inner md-grid" aria-label=Footer> <a href=../json_disable_tuple_reference_conversion/ class="md-footer__link md-footer__link--prev" aria-label="Previous: JSON_DISABLE_TUPLE_REFERENCE_CONVERSION"> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </div> <div class=md-footer__title> <span class=md-footer__direction> Previous </span> <div class=md-ellipsis> JSON_DISABLE_TUPLE_REFERENCE_CONVERSION </div> </div> </a> <a href=../json_has_cpp_11/ class="md-footer__link md-footer__link--next" aria-label="Next: JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26"> <div class=md-footer__title> <span class=md-footer__direction> Next </span> <div class=md-ellipsis> JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26 </div> </div> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg> </div> </a> </nav> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> <div class=md-copyright__highlight> Copyright &copy; 2013-2026 Niels Lohmann </div> </div> <div class=md-social> <a href="https://github.com/nlohmann" target="_blank" rel="noopener" title="github.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 Line truncated
</code></pre></div> </details> <h2 id=see-also>See also<a class=headerlink href=#see-also title="Permanent link">&para;</a></h2> <ul> <li><a href=../../basic_json/parse/ ><code>parse</code></a> - deserialize from a compatible input</li> <li><a href=../../basic_json/sax_parse/ ><code>sax_parse</code></a> - generate <abbr title="Simple API for XML">SAX</abbr> events</li> <li><a href=../json_disable_stream_bulk_scan/ ><code>JSON_DISABLE_STREAM_BULK_SCAN</code></a> - read a <code>std::istream</code> one character at a time</li> <li><a href=../../../features/parsing/#input-sources-and-performance>Parsing: input sources and performance</a> - how input sources affect parsing performance</li> <li><a href=../../../features/parsing/large_and_partial_input/ >Large, Streamed, and Partial Input</a> - chunked, concatenated, and very large input</li> </ul> <h2 id=version-history>Version history<a class=headerlink href=#version-history title="Permanent link">&para;</a></h2> <ul> <li>Added in version 3.13.0 <span class=unreleased-version title="Not part of a release yet; the latest release is 3.12.0.">unreleased</span>.</li> </ul> <!-- https://squidfunk.github.io/mkdocs-material/reference/tooltips/#adding-a-glossary --> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date" title="November 7, 2026 09:11:09 UTC">November 7, 2026</span> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <nav class="md-footer__inner md-grid" aria-label=Footer> <a href=../json_disable_tuple_reference_conversion/ class="md-footer__link md-footer__link--prev" aria-label="Previous: JSON_DISABLE_TUPLE_REFERENCE_CONVERSION"> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </div> <div class=md-footer__title> <span class=md-footer__direction> Previous </span> <div class=md-ellipsis> JSON_DISABLE_TUPLE_REFERENCE_CONVERSION </div> </div> </a> <a href=../json_has_cpp_11/ class="md-footer__link md-footer__link--next" aria-label="Next: JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26"> <div class=md-footer__title> <span class=md-footer__direction> Next </span> <div class=md-ellipsis> JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26 </div> </div> <div class="md-footer__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg> </div> </a> </nav> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> <div class=md-copyright__highlight> Copyright &copy; 2013-2026 Niels Lohmann </div> </div> <div class=md-social> <a href="https://github.com/nlohmann" target="_blank" rel="noopener" title="github.com" class="md-social__link"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 512 512"><!-- Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 Line truncated
@@ -4,7 +4,7 @@
#define JSON_DISABLE_UNLOCKED_FILE_IO /* value */
```
When defined to `1`, parsing from a `FILE*` reads every character with `std::fgetc`, as in version 3.12.0 and earlier, instead of locking the file once and reading it with the unlocked stdio functions.
When defined to `1`, parsing from a `FILE*` reads every character with `std::fgetc`, as in version 3.12.0 and earlier, instead of locking the file once and reading it with the unlocked stdio functions. This also turns off the scan of the `FILE`'s buffer in bulk (see below), which [`JSON_DISABLE_STREAM_BULK_SCAN`](https://json.nlohmann.me/api/macros/json_disable_stream_bulk_scan/index.md) does not affect.
It does not change any result: values, exceptions, and the position of the file after parsing are the same either way. Only the speed and the locking of the file differ (see the notes on locking below).
@@ -32,7 +32,9 @@ Instead, the parser locks the file once when parsing starts and unlocks it when
| Microsoft (MSVC, clang-cl) | `_lock_file`, `_fgetc_nolock`, `_unlock_file` |
| others (e.g., musl, MinGW, newlib) | `std::fgetc`, as before |
This makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with glibc, whose locking is cheaper. The binary formats ([`from_cbor`](https://json.nlohmann.me/api/basic_json/from_cbor/index.md), [`from_msgpack`](https://json.nlohmann.me/api/basic_json/from_msgpack/index.md), ...) read from a `FILE*` the same way.
With glibc and the Apple C library, the parser also scans the characters that the `FILE` already holds in its buffer in bulk, as it scans the get area of a stream (see [`JSON_DISABLE_STREAM_BULK_SCAN`](https://json.nlohmann.me/api/macros/json_disable_stream_bulk_scan/index.md)): it reads the same fields of the `FILE` that the C library's own `getc_unlocked` reads, and it consumes exactly the characters that `getc_unlocked` would have returned, so the file is left where it was left before.
Locking the file once makes parsing from a `FILE*` 3 to 4 times as fast with the Apple C library and 1.1 to 1.3 times as fast with glibc, whose locking is cheaper. Scanning the buffer in bulk makes `parse()` another 1.7 to 2.6 times as fast (and `accept()` 2.9 to 4.4 times), about as fast as parsing from a `std::ifstream`. The binary formats ([`from_cbor`](https://json.nlohmann.me/api/basic_json/from_cbor/index.md), [`from_msgpack`](https://json.nlohmann.me/api/basic_json/from_msgpack/index.md), ...) read from a `FILE*` the same way.
Locking