fixed adding file problem
[c11concurrency-benchmarks.git] / gdax-orderbook-hpp / demo / dependencies / rapidjson-1.1.0 / doc / stream.zh-cn.md
1 # 流
2
3 在 RapidJSON 中,`rapidjson::Stream` 是用於读写 JSON 的概念(概念是指 C++ 的 concept)。在这里我们先介绍如何使用 RapidJSON 提供的各种流。然后再看看如何自行定义流。
4
5 [TOC]
6
7 # 内存流 {#MemoryStreams}
8
9 内存流把 JSON 存储在内存之中。
10
11 ## StringStream(输入){#StringStream}
12
13 `StringStream` 是最基本的输入流,它表示一个完整的、只读的、存储于内存的 JSON。它在 `rapidjson/rapidjson.h` 中定义。
14
15 ~~~~~~~~~~cpp
16 #include "rapidjson/document.h" // 会包含 "rapidjson/rapidjson.h"
17
18 using namespace rapidjson;
19
20 // ...
21 const char json[] = "[1, 2, 3, 4]";
22 StringStream s(json);
23
24 Document d;
25 d.ParseStream(s);
26 ~~~~~~~~~~
27
28 由于这是非常常用的用法,RapidJSON 提供 `Document::Parse(const char*)` 去做完全相同的事情:
29
30 ~~~~~~~~~~cpp
31 // ...
32 const char json[] = "[1, 2, 3, 4]";
33 Document d;
34 d.Parse(json);
35 ~~~~~~~~~~
36
37 需要注意,`StringStream` 是 `GenericStringStream<UTF8<> >` 的 typedef,使用者可用其他编码类去代表流所使用的字符集。
38
39 ## StringBuffer(输出){#StringBuffer}
40
41 `StringBuffer` 是一个简单的输出流。它分配一个内存缓冲区,供写入整个 JSON。可使用 `GetString()` 来获取该缓冲区。
42
43 ~~~~~~~~~~cpp
44 #include "rapidjson/stringbuffer.h"
45
46 StringBuffer buffer;
47 Writer<StringBuffer> writer(buffer);
48 d.Accept(writer);
49
50 const char* output = buffer.GetString();
51 ~~~~~~~~~~
52
53 当缓冲区满溢,它将自动增加容量。缺省容量是 256 个字符(UTF8 是 256 字节,UTF16 是 512 字节等)。使用者能自行提供分配器及初始容量。
54
55 ~~~~~~~~~~cpp
56 StringBuffer buffer1(0, 1024); // 使用它的分配器,初始大小 = 1024
57 StringBuffer buffer2(allocator, 1024);
58 ~~~~~~~~~~
59
60 如无设置分配器,`StringBuffer` 会自行实例化一个内部分配器。
61
62 相似地,`StringBuffer` 是 `GenericStringBuffer<UTF8<> >` 的 typedef。
63
64 # 文件流 {#FileStreams}
65
66 当要从文件解析一个 JSON,你可以把整个 JSON 读入内存并使用上述的 `StringStream`。
67
68 然而,若 JSON 很大,或是内存有限,你可以改用 `FileReadStream`。它只会从文件读取一部分至缓冲区,然后让那部分被解析。若缓冲区的字符都被读完,它会再从文件读取下一部分。
69
70 ## FileReadStream(输入) {#FileReadStream}
71
72 `FileReadStream` 通过 `FILE` 指针读取文件。使用者需要提供一个缓冲区。
73
74 ~~~~~~~~~~cpp
75 #include "rapidjson/filereadstream.h"
76 #include <cstdio>
77
78 using namespace rapidjson;
79
80 FILE* fp = fopen("big.json", "rb"); // 非 Windows 平台使用 "r"
81
82 char readBuffer[65536];
83 FileReadStream is(fp, readBuffer, sizeof(readBuffer));
84
85 Document d;
86 d.ParseStream(is);
87
88 fclose(fp);
89 ~~~~~~~~~~
90
91 与 `StringStreams` 不一样,`FileReadStream` 是一个字节流。它不处理编码。若文件并非 UTF-8 编码,可以把字节流用 `EncodedInputStream` 包装。我们很快会讨论这个问题。
92
93 除了读取文件,使用者也可以使用 `FileReadStream` 来读取 `stdin`。
94
95 ## FileWriteStream(输出){#FileWriteStream}
96
97 `FileWriteStream` 是一个含缓冲功能的输出流。它的用法与 `FileReadStream` 非常相似。
98
99 ~~~~~~~~~~cpp
100 #include "rapidjson/filewritestream.h"
101 #include <cstdio>
102
103 using namespace rapidjson;
104
105 Document d;
106 d.Parse(json);
107 // ...
108
109 FILE* fp = fopen("output.json", "wb"); // 非 Windows 平台使用 "w"
110
111 char writeBuffer[65536];
112 FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
113
114 Writer<FileWriteStream> writer(os);
115 d.Accept(writer);
116
117 fclose(fp);
118 ~~~~~~~~~~
119
120 它也可以把输出导向 `stdout`。
121
122 # iostream 包装类 {#iostreamWrapper}
123
124 基于用户的要求,RapidJSON 提供了正式的 `std::basic_istream` 和 `std::basic_ostream` 包装类。然而,请注意其性能会大大低于以上的其他流。
125
126 ## IStreamWrapper {#IStreamWrapper}
127
128 `IStreamWrapper` 把任何继承自 `std::istream` 的类(如 `std::istringstream`、`std::stringstream`、`std::ifstream`、`std::fstream`)包装成 RapidJSON 的输入流。
129
130 ~~~cpp
131 #include <rapidjson/document.h>
132 #include <rapidjson/istreamwrapper.h>
133 #include <fstream>
134
135 using namespace rapidjson;
136 using namespace std;
137
138 ifstream ifs("test.json");
139 IStreamWrapper isw(ifs);
140
141 Document d;
142 d.ParseStream(isw);
143 ~~~
144
145 对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
146
147 ## OStreamWrapper {#OStreamWrapper}
148
149 相似地,`OStreamWrapper` 把任何继承自 `std::ostream` 的类(如 `std::ostringstream`、`std::stringstream`、`std::ofstream`、`std::fstream`)包装成 RapidJSON 的输出流。
150
151 ~~~cpp
152 #include <rapidjson/document.h>
153 #include <rapidjson/ostreamwrapper.h>
154 #include <rapidjson/writer.h>
155 #include <fstream>
156
157 using namespace rapidjson;
158 using namespace std;
159
160 Document d;
161 d.Parse(json);
162
163 // ...
164
165 ofstream ofs("output.json");
166 OStreamWrapper osw(ofs);
167
168 Writer<OStreamWrapper> writer(osw);
169 d.Accept(writer);
170 ~~~
171
172 对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
173
174 # 编码流 {#EncodedStreams}
175
176 编码流(encoded streams)本身不存储 JSON,它们是通过包装字节流来提供基本的编码/解码功能。
177
178 如上所述,我们可以直接读入 UTF-8 字节流。然而,UTF-16 及 UTF-32 有字节序(endian)问题。要正确地处理字节序,需要在读取时把字节转换成字符(如对 UTF-16 使用 `wchar_t`),以及在写入时把字符转换为字节。
179
180 除此以外,我们也需要处理 [字节顺序标记(byte order mark, BOM)](http://en.wikipedia.org/wiki/Byte_order_mark)。当从一个字节流读取时,需要检测 BOM,或者仅仅是把存在的 BOM 消去。当把 JSON 写入字节流时,也可选择写入 BOM。
181
182 若一个流的编码在编译期已知,你可使用 `EncodedInputStream` 及 `EncodedOutputStream`。若一个流可能存储 UTF-8、UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE 的 JSON,并且编码只能在运行时得知,你便可以使用 `AutoUTFInputStream` 及 `AutoUTFOutputStream`。这些流定义在 `rapidjson/encodedstream.h`。
183
184 注意到,这些编码流可以施于文件以外的流。例如,你可以用编码流包装内存中的文件或自定义的字节流。
185
186 ## EncodedInputStream {#EncodedInputStream}
187
188 `EncodedInputStream` 含两个模板参数。第一个是 `Encoding` 类型,例如定义于 `rapidjson/encodings.h` 的 `UTF8`、`UTF16LE`。第二个参数是被包装的流的类型。
189
190 ~~~~~~~~~~cpp
191 #include "rapidjson/document.h"
192 #include "rapidjson/filereadstream.h"   // FileReadStream
193 #include "rapidjson/encodedstream.h"    // EncodedInputStream
194 #include <cstdio>
195
196 using namespace rapidjson;
197
198 FILE* fp = fopen("utf16le.json", "rb"); // 非 Windows 平台使用 "r"
199
200 char readBuffer[256];
201 FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
202
203 EncodedInputStream<UTF16LE<>, FileReadStream> eis(bis);  // 用 eis 包装 bis
204
205 Document d; // Document 为 GenericDocument<UTF8<> > 
206 d.ParseStream<0, UTF16LE<> >(eis);  // 把 UTF-16LE 文件解析至内存中的 UTF-8
207
208 fclose(fp);
209 ~~~~~~~~~~
210
211 ## EncodedOutputStream {#EncodedOutputStream}
212
213 `EncodedOutputStream` 也是相似的,但它的构造函数有一个 `bool putBOM` 参数,用于控制是否在输出字节流写入 BOM。
214
215 ~~~~~~~~~~cpp
216 #include "rapidjson/filewritestream.h"  // FileWriteStream
217 #include "rapidjson/encodedstream.h"    // EncodedOutputStream
218 #include <cstdio>
219
220 Document d;         // Document 为 GenericDocument<UTF8<> > 
221 // ...
222
223 FILE* fp = fopen("output_utf32le.json", "wb"); // 非 Windows 平台使用 "w"
224
225 char writeBuffer[256];
226 FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
227
228 typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
229 OutputStream eos(bos, true);   // 写入 BOM
230
231 Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
232 d.Accept(writer);   // 这里从内存的 UTF-8 生成 UTF32-LE 文件
233
234 fclose(fp);
235 ~~~~~~~~~~
236
237 ## AutoUTFInputStream {#AutoUTFInputStream}
238
239 有时候,应用软件可能需要㲃理所有可支持的 JSON 编码。`AutoUTFInputStream` 会先使用 BOM 来检测编码。若 BOM 不存在,它便会使用合法 JSON 的特性来检测。若两种方法都失败,它就会倒退至构造函数提供的 UTF 类型。
240
241 由于字符(编码单元/code unit)可能是 8 位、16 位或 32 位,`AutoUTFInputStream` 需要一个能至少储存 32 位的字符类型。我们可以使用 `unsigned` 作为模板参数:
242
243 ~~~~~~~~~~cpp
244 #include "rapidjson/document.h"
245 #include "rapidjson/filereadstream.h"   // FileReadStream
246 #include "rapidjson/encodedstream.h"    // AutoUTFInputStream
247 #include <cstdio>
248
249 using namespace rapidjson;
250
251 FILE* fp = fopen("any.json", "rb"); // 非 Windows 平台使用 "r"
252
253 char readBuffer[256];
254 FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
255
256 AutoUTFInputStream<unsigned, FileReadStream> eis(bis);  // 用 eis 包装 bis
257
258 Document d;         // Document 为 GenericDocument<UTF8<> > 
259 d.ParseStream<0, AutoUTF<unsigned> >(eis); // 把任何 UTF 编码的文件解析至内存中的 UTF-8
260
261 fclose(fp);
262 ~~~~~~~~~~
263
264 当要指定流的编码,可使用上面例子中 `ParseStream()` 的参数 `AutoUTF<CharType>`。
265
266 你可以使用 `UTFType GetType()` 去获取 UTF 类型,并且用 `HasBOM()` 检测输入流是否含有 BOM。
267
268 ## AutoUTFOutputStream {#AutoUTFOutputStream}
269
270 相似地,要在运行时选择输出的编码,我们可使用 `AutoUTFOutputStream`。这个类本身并非「自动」。你需要在运行时指定 UTF 类型,以及是否写入 BOM。
271
272 ~~~~~~~~~~cpp
273 using namespace rapidjson;
274
275 void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
276     char writeBuffer[256];
277     FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
278
279     typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream;
280     OutputStream eos(bos, type, putBOM);
281     
282     Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
283     d.Accept(writer);
284 }
285 ~~~~~~~~~~
286
287 `AutoUTFInputStream`/`AutoUTFOutputStream` 是比 `EncodedInputStream`/`EncodedOutputStream` 方便。但前者会产生一点运行期额外开销。
288
289 # 自定义流 {#CustomStream}
290
291 除了内存/文件流,使用者可创建自行定义适配 RapidJSON API 的流类。例如,你可以创建网络流、从压缩文件读取的流等等。
292
293 RapidJSON 利用模板结合不同的类型。只要一个类包含所有所需的接口,就可以作为一个流。流的接合定义在 `rapidjson/rapidjson.h` 的注释里:
294
295 ~~~~~~~~~~cpp
296 concept Stream {
297     typename Ch;    //!< 流的字符类型
298
299     //! 从流读取当前字符,不移动读取指针(read cursor)
300     Ch Peek() const;
301
302     //! 从流读取当前字符,移动读取指针至下一字符。
303     Ch Take();
304
305     //! 获取读取指针。
306     //! \return 从开始以来所读过的字符数量。
307     size_t Tell();
308
309     //! 从当前读取指针开始写入操作。
310     //! \return 返回开始写入的指针。
311     Ch* PutBegin();
312
313     //! 写入一个字符。
314     void Put(Ch c);
315
316     //! 清空缓冲区。
317     void Flush();
318
319     //! 完成写作操作。
320     //! \param begin PutBegin() 返回的开始写入指针。
321     //! \return 已写入的字符数量。
322     size_t PutEnd(Ch* begin);
323 }
324 ~~~~~~~~~~
325
326 输入流必须实现 `Peek()`、`Take()` 及 `Tell()`。
327 输出流必须实现 `Put()` 及 `Flush()`。
328 `PutBegin()` 及 `PutEnd()` 是特殊的接口,仅用于原位(*in situ*)解析。一般的流不需实现它们。然而,即使接口不需用于某些流,仍然需要提供空实现,否则会产生编译错误。
329
330 ## 例子:istream 的包装类 {#ExampleIStreamWrapper}
331
332 以下的简单例子是 `std::istream` 的包装类,它只需现 3 个函数。
333
334 ~~~~~~~~~~cpp
335 class MyIStreamWrapper {
336 public:
337     typedef char Ch;
338
339     MyIStreamWrapper(std::istream& is) : is_(is) {
340     }
341
342     Ch Peek() const { // 1
343         int c = is_.peek();
344         return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
345     }
346
347     Ch Take() { // 2
348         int c = is_.get();
349         return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
350     }
351
352     size_t Tell() const { return (size_t)is_.tellg(); } // 3
353
354     Ch* PutBegin() { assert(false); return 0; }
355     void Put(Ch) { assert(false); }
356     void Flush() { assert(false); }
357     size_t PutEnd(Ch*) { assert(false); return 0; }
358
359 private:
360     MyIStreamWrapper(const MyIStreamWrapper&);
361     MyIStreamWrapper& operator=(const MyIStreamWrapper&);
362
363     std::istream& is_;
364 };
365 ~~~~~~~~~~
366
367 使用者能用它来包装 `std::stringstream`、`std::ifstream` 的实例。
368
369 ~~~~~~~~~~cpp
370 const char* json = "[1,2,3,4]";
371 std::stringstream ss(json);
372 MyIStreamWrapper is(ss);
373
374 Document d;
375 d.ParseStream(is);
376 ~~~~~~~~~~
377
378 但要注意,由于标准库的内部开销问,此实现的性能可能不如 RapidJSON 的内存/文件流。
379
380 ## 例子:ostream 的包装类 {#ExampleOStreamWrapper}
381
382 以下的例子是 `std::istream` 的包装类,它只需实现 2 个函数。
383
384 ~~~~~~~~~~cpp
385 class MyOStreamWrapper {
386 public:
387     typedef char Ch;
388
389     OStreamWrapper(std::ostream& os) : os_(os) {
390     }
391
392     Ch Peek() const { assert(false); return '\0'; }
393     Ch Take() { assert(false); return '\0'; }
394     size_t Tell() const {  }
395
396     Ch* PutBegin() { assert(false); return 0; }
397     void Put(Ch c) { os_.put(c); }                  // 1
398     void Flush() { os_.flush(); }                   // 2
399     size_t PutEnd(Ch*) { assert(false); return 0; }
400
401 private:
402     MyOStreamWrapper(const MyOStreamWrapper&);
403     MyOStreamWrapper& operator=(const MyOStreamWrapper&);
404
405     std::ostream& os_;
406 };
407 ~~~~~~~~~~
408
409 使用者能用它来包装 `std::stringstream`、`std::ofstream` 的实例。
410
411 ~~~~~~~~~~cpp
412 Document d;
413 // ...
414
415 std::stringstream ss;
416 MyOStreamWrapper os(ss);
417
418 Writer<MyOStreamWrapper> writer(os);
419 d.Accept(writer);
420 ~~~~~~~~~~
421
422 但要注意,由于标准库的内部开销问,此实现的性能可能不如 RapidJSON 的内存/文件流。
423
424 # 总结 {#Summary}
425
426 本节描述了 RapidJSON 提供的各种流的类。内存流很简单。若 JSON 存储在文件中,文件流可减少 JSON 解析及生成所需的内存量。编码流在字节流和字符流之间作转换。最后,使用者可使用一个简单接口创建自定义的流。