Welcome to mirror list, hosted at ThFree Co, Russian Federation.

md_doc_stream_8zh-cn.html « zh-cn - github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fb94edc903b3df7476eb2efa33541c929c482f6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
<!-- HTML header for doxygen 1.8.7-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>RapidJSON: 流</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { searchBox.OnSelectItem(0); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygenextra.css" rel="stylesheet" type="text/css"/>
</head>
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  ga('create', 'UA-63929386-1', 'auto');
  ga('send', 'pageview');
</script>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="搜索" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
<!-- end header part -->
<!-- 制作者 Doxygen 1.8.7 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'搜索');
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('md_doc_stream_8zh-cn.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>全部</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>类</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>命名空间</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark">&#160;</span>文件</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark">&#160;</span>函数</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark">&#160;</span>变量</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark">&#160;</span>类型定义</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark">&#160;</span>枚举</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark">&#160;</span>枚举值</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark">&#160;</span>友元</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(10)"><span class="SelectionMark">&#160;</span>宏定义</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(11)"><span class="SelectionMark">&#160;</span>组</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(12)"><span class="SelectionMark">&#160;</span>页</a></div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">流 </div>  </div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>目录</h3>
<ul><li class="level1"><a href="#MemoryStreams">内存流</a><ul><li class="level2"><a href="#StringStream">StringStream(输入)</a></li>
<li class="level2"><a href="#StringBuffer">StringBuffer(输出)</a></li>
</ul>
</li>
<li class="level1"><a href="#FileStreams">文件流</a><ul><li class="level2"><a href="#FileReadStream">FileReadStream(输入)</a></li>
<li class="level2"><a href="#FileWriteStream">FileWriteStream(输出)</a></li>
</ul>
</li>
<li class="level1"><a href="#EncodedStreams">编码流</a><ul><li class="level2"><a href="#EncodedInputStream">EncodedInputStream</a></li>
<li class="level2"><a href="#EncodedOutputStream">EncodedOutputStream</a></li>
<li class="level2"><a href="#AutoUTFInputStream">AutoUTFInputStream</a></li>
<li class="level2"><a href="#AutoUTFOutputStream">AutoUTFOutputStream</a></li>
</ul>
</li>
<li class="level1"><a href="#CustomStream">自定义流</a><ul><li class="level2"><a href="#ExampleIStreamWrapper">例子:istream的包装类</a></li>
<li class="level2"><a href="#ExampleOStreamWrapper">例子:ostream的包装类</a></li>
</ul>
</li>
<li class="level1"><a href="#Summary">总结</a></li>
</ul>
</div>
<div class="textblock"><p>在RapidJSON中,<code><a class="el" href="classrapidjson_1_1_stream.html" title="Concept for reading and writing characters. ">rapidjson::Stream</a></code>是用於读写JSON的概念(概念是指C++的concept)。在这里我们先介绍如何使用RapidJSON提供的各种流。然后再看看如何自行定义流。</p>
<h1><a class="anchor" id="MemoryStreams"></a>
内存流</h1>
<p>内存流把JSON存储在内存之中。</p>
<h2><a class="anchor" id="StringStream"></a>
StringStream(输入)</h2>
<p><code>StringStream</code>是最基本的输入流,它表示一个完整的、只读的、存储于内存的JSON。它在<code><a class="el" href="rapidjson_8h.html" title="common definitions and configuration ">rapidjson/rapidjson.h</a></code>中定义。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="document_8h.html">rapidjson/document.h</a>&quot;</span> <span class="comment">// 会包含 &quot;rapidjson/rapidjson.h&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> json[] = <span class="stringliteral">&quot;[1, 2, 3, 4]&quot;</span>;</div>
<div class="line"><a class="code" href="structrapidjson_1_1_generic_string_stream.html">StringStream</a> s(json);</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">Document</a> d;</div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">ParseStream</a>(s);</div>
</div><!-- fragment --><p>由于这是非常常用的用法,RapidJSON提供<code>Document::Parse(const char*)</code>去做完全相同的事情:</p>
<div class="fragment"><div class="line"><span class="comment">// ...</span></div>
<div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> json[] = <span class="stringliteral">&quot;[1, 2, 3, 4]&quot;</span>;</div>
<div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;</div>
<div class="line">d.Parse(json);</div>
</div><!-- fragment --><p>需要注意,<code>StringStream</code>是<code>GenericStringStream&lt;UTF8&lt;&gt; &gt;</code>的typedef,使用者可用其他编码类去代表流所使用的字符集。</p>
<h2><a class="anchor" id="StringBuffer"></a>
StringBuffer(输出)</h2>
<p><code>StringBuffer</code>是一个简单的输出流。它分配一个内存缓冲区,供写入整个JSON。可使用<code>GetString()</code>来获取该缓冲区。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;rapidjson/stringbuffer.h&quot;</span></div>
<div class="line"></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ac0765ea91f41539645c4b78689d03f21">StringBuffer</a> buffer;</div>
<div class="line">Writer&lt;StringBuffer&gt; writer(buffer);</div>
<div class="line">d.Accept(writer);</div>
<div class="line"></div>
<div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span>* output = buffer.GetString();</div>
</div><!-- fragment --><p>当缓冲区满溢,它将自动增加容量。缺省容量是256个字符(UTF8是256字节,UTF16是512字节等)。使用者能自行提供分配器及初始容量。</p>
<div class="fragment"><div class="line"><a class="code" href="namespacerapidjson.html#ac0765ea91f41539645c4b78689d03f21">StringBuffer</a> buffer1(0, 1024); <span class="comment">// 使用它的分配器,初始大小 = 1024</span></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ac0765ea91f41539645c4b78689d03f21">StringBuffer</a> buffer2(allocator, 1024);</div>
</div><!-- fragment --><p>如无设置分配器,<code>StringBuffer</code>会自行实例化一个内部分配器。</p>
<p>相似地,<code>StringBuffer</code>是<code>GenericStringBuffer&lt;UTF8&lt;&gt; &gt;</code>的typedef。</p>
<h1><a class="anchor" id="FileStreams"></a>
文件流</h1>
<p>当要从文件解析一个JSON,你可以把整个JSON读入内存并使用上述的<code>StringStream</code>。</p>
<p>然而,若JSON很大,或是内存有限,你可以改用<code>FileReadStream</code>。它只会从文件读取一部分至缓冲区,然后让那部分被解析。若缓冲区的字符都被读完,它会再从文件读取下一部分。</p>
<h2><a class="anchor" id="FileReadStream"></a>
FileReadStream(输入)</h2>
<p><code>FileReadStream</code>通过<code>FILE</code>指针读取文件。使用者需要提供一个缓冲区。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;rapidjson/filereadstream.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;big.json&quot;</span>, <span class="stringliteral">&quot;rb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;r&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> readBuffer[65536];</div>
<div class="line"><a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a> is(fp, readBuffer, <span class="keyword">sizeof</span>(readBuffer));</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">Document</a> d;</div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">ParseStream</a>(is);</div>
<div class="line"></div>
<div class="line">fclose(fp);</div>
</div><!-- fragment --><p>与<code>StringStreams</code>不一样,<code>FileReadStream</code>是一个字节流。它不处理编码。若文件并非UTF-8编码,可以把字节流用<code>EncodedInputStream</code>包装。我们很快会讨论这个问题。</p>
<p>除了读取文件,使用者也可以使用<code>FileReadStream</code>来读取<code>stdin</code>。</p>
<h2><a class="anchor" id="FileWriteStream"></a>
FileWriteStream(输出)</h2>
<p><code>FileWriteStream</code>是一个含缓冲功能的输出流。它的用法与<code>FileReadStream</code>非常相似。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;rapidjson/filewritestream.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">Document</a> d;</div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#aea842b533a858c9a3861451ad9e8642c">Parse</a>(json);</div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;output.json&quot;</span>, <span class="stringliteral">&quot;wb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;w&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> writeBuffer[65536];</div>
<div class="line"><a class="code" href="classrapidjson_1_1_file_write_stream.html">FileWriteStream</a> os(fp, writeBuffer, <span class="keyword">sizeof</span>(writeBuffer));</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_writer.html">Writer&lt;FileWriteStream&gt;</a> writer(os);</div>
<div class="line">d.Accept(writer);</div>
<div class="line"></div>
<div class="line">fclose(fp);</div>
</div><!-- fragment --><p>它也可以把输出导向<code>stdout</code>。</p>
<h1><a class="anchor" id="EncodedStreams"></a>
编码流</h1>
<p>编码流(encoded streams)本身不存储JSON,它们是通过包装字节流来提供基本的编码/解码功能。</p>
<p>如上所述,我们可以直接读入UTF-8字节流。然而,UTF-16及UTF-32有字节序(endian)问题。要正确地处理字节序,需要在读取时把字节转换成字符(如对UTF-16使用<code>wchar_t</code>),以及在写入时把字符转换为字节。</p>
<p>除此以外,我们也需要处理<a href="http://en.wikipedia.org/wiki/Byte_order_mark">字节顺序标记(byte order mark, BOM)</a>。当从一个字节流读取时,需要检测BOM,或者仅仅是把存在的BOM消去。当把JSON写入字节流时,也可选择写入BOM。</p>
<p>若一个流的编码在编译期已知,你可使用<code>EncodedInputStream</code>及<code>EncodedOutputStream</code>。若一个流可能存储UTF-8、UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE的JSON,并且编码只能在运行时得知,你便可以使用<code>AutoUTFInputStream</code>及<code>AutoUTFOutputStream</code>。这些流定义在<code><a class="el" href="encodedstream_8h_source.html">rapidjson/encodedstream.h</a></code>。</p>
<p>注意到,这些编码流可以施于文件以外的流。例如,你可以用编码流包装内存中的文件或自定义的字节流。</p>
<h2><a class="anchor" id="EncodedInputStream"></a>
EncodedInputStream</h2>
<p><code>EncodedInputStream</code>含两个模板参数。第一个是<code>Encoding</code>类型,例如定义于<code><a class="el" href="encodings_8h_source.html">rapidjson/encodings.h</a></code>的<code>UTF8</code>、<code>UTF16LE</code>。第二个参数是被包装的流的类型。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="document_8h.html">rapidjson/document.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/filereadstream.h&quot;</span>   <span class="comment">// FileReadStream</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/encodedstream.h&quot;</span>    <span class="comment">// EncodedInputStream</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;utf16le.json&quot;</span>, <span class="stringliteral">&quot;rb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;r&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> readBuffer[256];</div>
<div class="line"><a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a> bis(fp, readBuffer, <span class="keyword">sizeof</span>(readBuffer));</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_encoded_input_stream.html">EncodedInputStream&lt;UTF16LE&lt;&gt;</a>, <a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a>&gt; eis(bis);  <span class="comment">// 用eis包装bis</span></div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">Document</a> d; <span class="comment">// Document为GenericDocument&lt;UTF8&lt;&gt; &gt; </span></div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">ParseStream</a>&lt;0, <a class="code" href="structrapidjson_1_1_u_t_f16_l_e.html">UTF16LE&lt;&gt;</a> &gt;(eis);  <span class="comment">// 把UTF-16LE文件解析至内存中的UTF-8</span></div>
<div class="line"></div>
<div class="line">fclose(fp);</div>
</div><!-- fragment --><h2><a class="anchor" id="EncodedOutputStream"></a>
EncodedOutputStream</h2>
<p><code>EncodedOutputStream</code>也是相似的,但它的构造函数有一个<code>bool putBOM</code>参数,用于控制是否在输出字节流写入BOM。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;rapidjson/filewritestream.h&quot;</span>  <span class="comment">// FileWriteStream</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/encodedstream.h&quot;</span>    <span class="comment">// EncodedOutputStream</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;         <span class="comment">// Document为GenericDocument&lt;UTF8&lt;&gt; &gt; </span></div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;output_utf32le.json&quot;</span>, <span class="stringliteral">&quot;wb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;w&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> writeBuffer[256];</div>
<div class="line">FileWriteStream bos(fp, writeBuffer, <span class="keyword">sizeof</span>(writeBuffer));</div>
<div class="line"></div>
<div class="line"><span class="keyword">typedef</span> EncodedOutputStream&lt;UTF32LE&lt;&gt;, FileWriteStream&gt; OutputStream;</div>
<div class="line">OutputStream eos(bos, <span class="keyword">true</span>);   <span class="comment">// 写入BOM</span></div>
<div class="line"></div>
<div class="line">Writer&lt;OutputStream, UTF32LE&lt;&gt;, UTF8&lt;&gt;&gt; writer(eos);</div>
<div class="line">d.Accept(writer);   <span class="comment">// 这里从内存的UTF-8生成UTF32-LE文件</span></div>
<div class="line"></div>
<div class="line">fclose(fp);</div>
</div><!-- fragment --><h2><a class="anchor" id="AutoUTFInputStream"></a>
AutoUTFInputStream</h2>
<p>有时候,应用软件可能需要㲃理所有可支持的JSON编码。<code>AutoUTFInputStream</code>会先使用BOM来检测编码。若BOM不存在,它便会使用合法JSON的特性来检测。若两种方法都失败,它就会倒退至构造函数提供的UTF类型。</p>
<p>由于字符(编码单元/code unit)可能是8位、16位或32位,<code>AutoUTFInputStream</code> 需要一个能至少储存32位的字符类型。我们可以使用<code>unsigned</code>作为模板参数:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="document_8h.html">rapidjson/document.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/filereadstream.h&quot;</span>   <span class="comment">// FileReadStream</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/encodedstream.h&quot;</span>    <span class="comment">// AutoUTFInputStream</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;any.json&quot;</span>, <span class="stringliteral">&quot;rb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;r&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> readBuffer[256];</div>
<div class="line"><a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a> bis(fp, readBuffer, <span class="keyword">sizeof</span>(readBuffer));</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_auto_u_t_f_input_stream.html">AutoUTFInputStream&lt;unsigned, FileReadStream&gt;</a> eis(bis);  <span class="comment">// 用eis包装bis</span></div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">Document</a> d;         <span class="comment">// Document为GenericDocument&lt;UTF8&lt;&gt; &gt; </span></div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">ParseStream</a>&lt;0, <a class="code" href="structrapidjson_1_1_auto_u_t_f.html">AutoUTF&lt;unsigned&gt;</a> &gt;(eis); <span class="comment">// 把任何UTF编码的文件解析至内存中的UTF-8</span></div>
<div class="line"></div>
<div class="line">fclose(fp);</div>
</div><!-- fragment --><p>当要指定流的编码,可使用上面例子中<code>ParseStream()</code>的参数<code>AutoUTF&lt;CharType&gt;</code>。</p>
<p>你可以使用<code>UTFType GetType()</code>去获取UTF类型,并且用<code>HasBOM()</code>检测输入流是否含有BOM。</p>
<h2><a class="anchor" id="AutoUTFOutputStream"></a>
AutoUTFOutputStream</h2>
<p>相似地,要在运行时选择输出的编码,我们可使用<code>AutoUTFOutputStream</code>。这个类本身并非「自动」。你需要在运行时指定UTF类型,以及是否写入BOM。</p>
<div class="fragment"><div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">void</span> WriteJSONFile(FILE* fp, <a class="code" href="namespacerapidjson.html#a4aacabc0f8cea1cd628f466d890773eb">UTFType</a> type, <span class="keywordtype">bool</span> putBOM, <span class="keyword">const</span> <a class="code" href="classrapidjson_1_1_generic_document.html">Document</a>&amp; d) {</div>
<div class="line">    <span class="keywordtype">char</span> writeBuffer[256];</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_file_write_stream.html">FileWriteStream</a> bos(fp, writeBuffer, <span class="keyword">sizeof</span>(writeBuffer));</div>
<div class="line"></div>
<div class="line">    <span class="keyword">typedef</span> <a class="code" href="classrapidjson_1_1_auto_u_t_f_output_stream.html">AutoUTFOutputStream&lt;unsigned, FileWriteStream&gt;</a> OutputStream;</div>
<div class="line">    OutputStream eos(bos, type, putBOM);</div>
<div class="line"></div>
<div class="line">    <a class="code" href="classrapidjson_1_1_writer.html">Writer&lt;OutputStream, UTF8&lt;&gt;</a>, <a class="code" href="structrapidjson_1_1_auto_u_t_f.html">AutoUTF&lt;&gt;</a> &gt; writer;</div>
<div class="line">    d.<a class="code" href="classrapidjson_1_1_generic_value.html#aeef0506cd1f8d703db4833c503f0657e">Accept</a>(writer);</div>
<div class="line">}</div>
</div><!-- fragment --><p><code>AutoUTFInputStream</code>/<code>AutoUTFOutputStream</code>是比<code>EncodedInputStream</code>/<code>EncodedOutputStream</code>方便。但前者会产生一点运行期额外开销。</p>
<h1><a class="anchor" id="CustomStream"></a>
自定义流</h1>
<p>除了内存/文件流,使用者可创建自行定义适配RapidJSON API的流类。例如,你可以创建网络流、从压缩文件读取的流等等。</p>
<p>RapidJSON利用模板结合不同的类型。只要一个类包含所有所需的接口,就可以作为一个流。流的接合定义在<code><a class="el" href="rapidjson_8h.html" title="common definitions and configuration ">rapidjson/rapidjson.h</a></code>的注释里:</p>
<div class="fragment"><div class="line">concept Stream {</div>
<div class="line">    <span class="keyword">typename</span> Ch;    <span class="comment">//!&lt; 流的字符类型</span></div>
<div class="line"><span class="comment"></span><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 从流读取当前字符,不移动读取指针(read cursor)</span></div>
<div class="line"><span class="comment"></span>    Ch Peek() <span class="keyword">const</span>;</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 从流读取当前字符,移动读取指针至下一字符。</span></div>
<div class="line"><span class="comment"></span>    Ch Take();</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 获取读取指针。</span></div>
<div class="line"><span class="comment">    //! \return 从开始以来所读过的字符数量。</span></div>
<div class="line"><span class="comment"></span>    <span class="keywordtype">size_t</span> Tell();</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 从当前读取指针开始写入操作。</span></div>
<div class="line"><span class="comment">    //! \return 返回开始写入的指针。</span></div>
<div class="line"><span class="comment"></span>    Ch* PutBegin();</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 写入一个字符。</span></div>
<div class="line"><span class="comment"></span>    <span class="keywordtype">void</span> Put(Ch c);</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 清空缓冲区。</span></div>
<div class="line"><span class="comment"></span>    <span class="keywordtype">void</span> Flush();</div>
<div class="line"><span class="comment"></span></div>
<div class="line"><span class="comment">    //! 完成写作操作。</span></div>
<div class="line"><span class="comment">    //! \param begin PutBegin()返回的开始写入指针。</span></div>
<div class="line"><span class="comment">    //! \return 已写入的字符数量。</span></div>
<div class="line"><span class="comment"></span>    <span class="keywordtype">size_t</span> PutEnd(Ch* begin);</div>
<div class="line">}</div>
</div><!-- fragment --><p>输入流必须实现<code>Peek()</code>、<code>Take()</code>及<code>Tell()</code>。 输出流必须实现<code>Put()</code>及<code>Flush()</code>。 <code>PutBegin()</code>及<code>PutEnd()</code>是特殊的接口,仅用于原位(*in situ*)解析。一般的流不需实现它们。然而,即使接口不需用于某些流,仍然需要提供空实现,否则会产生编译错误。</p>
<h2><a class="anchor" id="ExampleIStreamWrapper"></a>
例子:istream的包装类</h2>
<p>以下的例子是<code>std::istream</code>的包装类,它只需现3个函数。</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>IStreamWrapper {</div>
<div class="line"><span class="keyword">public</span>:</div>
<div class="line">    <span class="keyword">typedef</span> <span class="keywordtype">char</span> Ch;</div>
<div class="line"></div>
<div class="line">    IStreamWrapper(std::istream&amp; is) : is_(is) {</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    Ch Peek()<span class="keyword"> const </span>{ <span class="comment">// 1</span></div>
<div class="line">        <span class="keywordtype">int</span> c = is_.peek();</div>
<div class="line">        <span class="keywordflow">return</span> c == std::char_traits&lt;char&gt;::eof() ? <span class="charliteral">&#39;\0&#39;</span> : (Ch)c;</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    Ch Take() { <span class="comment">// 2</span></div>
<div class="line">        <span class="keywordtype">int</span> c = is_.get();</div>
<div class="line">        <span class="keywordflow">return</span> c == std::char_traits&lt;char&gt;::eof() ? <span class="charliteral">&#39;\0&#39;</span> : (Ch)c;</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">size_t</span> Tell()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> (<span class="keywordtype">size_t</span>)is_.tellg(); } <span class="comment">// 3</span></div>
<div class="line"></div>
<div class="line">    Ch* PutBegin() { assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> 0; }</div>
<div class="line">    <span class="keywordtype">void</span> Put(Ch) { assert(<span class="keyword">false</span>); }</div>
<div class="line">    <span class="keywordtype">void</span> Flush() { assert(<span class="keyword">false</span>); }</div>
<div class="line">    <span class="keywordtype">size_t</span> PutEnd(Ch*) { assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> 0; }</div>
<div class="line"></div>
<div class="line"><span class="keyword">private</span>:</div>
<div class="line">    IStreamWrapper(<span class="keyword">const</span> IStreamWrapper&amp;);</div>
<div class="line">    IStreamWrapper&amp; operator=(<span class="keyword">const</span> IStreamWrapper&amp;);</div>
<div class="line"></div>
<div class="line">    std::istream&amp; is_;</div>
<div class="line">};</div>
</div><!-- fragment --><p>使用者能用它来包装<code>std::stringstream</code>、<code>std::ifstream</code>的实例。</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span>* json = <span class="stringliteral">&quot;[1,2,3,4]&quot;</span>;</div>
<div class="line">std::stringstream ss(json);</div>
<div class="line">IStreamWrapper is(ss);</div>
<div class="line"></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;</div>
<div class="line">d.<a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">ParseStream</a>(is);</div>
</div><!-- fragment --><p>但要注意,由于标准库的内部开销问,此实现的性能可能不如RapidJSON的内存/文件流。</p>
<h2><a class="anchor" id="ExampleOStreamWrapper"></a>
例子:ostream的包装类</h2>
<p>以下的例子是<code>std::istream</code>的包装类,它只需实现2个函数。</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>OStreamWrapper {</div>
<div class="line"><span class="keyword">public</span>:</div>
<div class="line">    <span class="keyword">typedef</span> <span class="keywordtype">char</span> Ch;</div>
<div class="line"></div>
<div class="line">    OStreamWrapper(std::ostream&amp; os) : os_(os) {</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    Ch Peek()<span class="keyword"> const </span>{ assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> <span class="charliteral">&#39;\0&#39;</span>; }</div>
<div class="line">    Ch Take() { assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> <span class="charliteral">&#39;\0&#39;</span>; }</div>
<div class="line">    <span class="keywordtype">size_t</span> Tell()<span class="keyword"> const </span>{  }</div>
<div class="line"></div>
<div class="line">    Ch* PutBegin() { assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> 0; }</div>
<div class="line">    <span class="keywordtype">void</span> Put(Ch c) { os_.put(c); }                  <span class="comment">// 1</span></div>
<div class="line">    <span class="keywordtype">void</span> Flush() { os_.flush(); }                   <span class="comment">// 2</span></div>
<div class="line">    <span class="keywordtype">size_t</span> PutEnd(Ch*) { assert(<span class="keyword">false</span>); <span class="keywordflow">return</span> 0; }</div>
<div class="line"></div>
<div class="line"><span class="keyword">private</span>:</div>
<div class="line">    OStreamWrapper(<span class="keyword">const</span> OStreamWrapper&amp;);</div>
<div class="line">    OStreamWrapper&amp; operator=(<span class="keyword">const</span> OStreamWrapper&amp;);</div>
<div class="line"></div>
<div class="line">    std::ostream&amp; os_;</div>
<div class="line">};</div>
</div><!-- fragment --><p>使用者能用它来包装<code>std::stringstream</code>、<code>std::ofstream</code>的实例。</p>
<div class="fragment"><div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;</div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line"></div>
<div class="line">std::stringstream ss;</div>
<div class="line">OSStreamWrapper os(ss);</div>
<div class="line"></div>
<div class="line">Writer&lt;OStreamWrapper&gt; writer(os);</div>
<div class="line">d.Accept(writer);</div>
</div><!-- fragment --><p>但要注意,由于标准库的内部开销问,此实现的性能可能不如RapidJSON的内存/文件流。</p>
<h1><a class="anchor" id="Summary"></a>
总结</h1>
<p>本节描述了RapidJSON提供的各种流的类。内存流很简单。若JSON存储在文件中,文件流可减少JSON解析及生成所需的内存量。编码流在字节流和字符流之间作转换。最后,使用者可使用一个简单接口创建自定义的流。 </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.8.7-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
  </ul>
</div>
<script type="text/javascript">
    /* * * CONFIGURATION VARIABLES * * */
    var disqus_shortname = 'rapidjson-doc';
    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
	    var dt = document.createElement('div');
	    dt.id = "disqus_thread";
	    (document.getElementsByClassName('contents')[0]).appendChild(dt);
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
</body>
</html>