QCborStreamWriter Class
QCborStreamWriter 类是一个在单向流上运行的简单 CBOR 编码器。更多
头文件: | #include <QCborStreamWriter> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake: | QT += core |
- 所有成员(包括继承成员)的列表
- QCborStreamWriter 是Qt 中 CBOR 支持的一部分。
注意:该类中的所有函数都是可重入的。
公共函数
QCborStreamWriter(QByteArray *data) | |
QCborStreamWriter(QIODevice *device) | |
~QCborStreamWriter() | |
void | append(QCborKnownTags tag) |
void | append(QCborNegativeInteger n) |
void | append(QCborSimpleType st) |
void | append(QCborTag tag) |
void | append(QLatin1StringView str) |
void | append(QStringView str) |
void | append(bool b) |
void | append(const QByteArray &ba) |
void | append(double d) |
void | append(float f) |
void | append(qfloat16 f) |
void | append(qint64 i) |
void | append(quint64 u) |
void | append(std::nullptr_t) |
void | append(const char *str, qsizetype size = -1) |
void | appendByteString(const char *data, qsizetype len) |
void | appendNull() |
void | appendTextString(const char *utf8, qsizetype len) |
void | appendUndefined() |
QIODevice * | device() const |
bool | endArray() |
bool | endMap() |
void | setDevice(QIODevice *device) |
void | startArray() |
void | startArray(quint64 count) |
void | startMap() |
void | startMap(quint64 count) |
详细说明
该类可用于将 CBOR 内容流直接快速编码为QByteArray 或QIODevice 。CBOR 是简明二进制对象表示法(Concise Binary Object Representation),是一种非常紧凑的二进制数据编码形式,与 JSON 兼容。它是由 IETF 受限 RESTful 环境(CoRE)工作组创建的,该工作组已将其用于许多新的 RFC 中。它旨在与CoAP 协议一起使用。
QCborStreamWriter 提供了类似于 StAX 的 API,类似于QXmlStreamWriter 。它的级别较低,需要一些 CBOR 编码的知识。有关更简单的 API,请参阅QCborValue ,尤其是编码函数QCborValue::toCbor() 。
QCborStreamWriter 的典型用法是在目标QByteArray 或QIODevice 上创建对象,然后调用append() 中的一个重载函数,调用所需的编码类型。为创建数组和映射,QCborStreamWriter 提供了startArray() 和startMap() 重载,这些重载必须以相应的endArray() 和endMap() 函数结束。
下面的示例编码了相当于此 JSON 内容的内容:
{ "label":"journald", "autoDetect": false, "condition":"libs.journald", "output":[ "privateFeature" ] }
writer.startMap(4); // 4 elements in the map writer.append("label"_L1); writer.append("journald"_L1); writer.append("autoDetect"_L1); writer.append(false); writer.append("condition"_L1); writer.append("libs.journald"_L1); writer.append("output"_L1); writer.startArray(1); writer.append("privateFeature"_L1); writer.endArray(); writer.endMap();
支持 CBOR
QCborStreamWriter 支持创建规范流和严格流所需的所有 CBOR 功能。它实现了RFC 7049 中指定的几乎所有功能。
下表列出了 QCborStreamWriter 支持的 CBOR 特性。
特性 | 支持 |
---|---|
无符号数 | 是(全范围) |
负数 | 是(全范围) |
字节字符串 | 是 |
文本字符串 | 是 |
分块字符串 | 无 |
标签 | 是(任意) |
布尔 | 布尔 |
空 | 是 |
未定义 | 是 |
任意简单值 | 是 |
半精度浮点数(16 位) | 是 |
单精度浮点数(32 位) | 是 |
双精度浮点运算(64 位) | 是 |
无穷大和 NaN 浮点数 | 是 |
确定长度的数组和映射 | 是 |
不定长数组和映射 | 是 |
除字符串和整数外的映射键类型 | 是(任意) |
规范 CBOR 编码
RFC 7049 第 3.9 节定义了规范 CBOR 编码。规范编码不是 Qt CBOR 解码功能的要求,但某些协议可能需要它。特别是那些要求能以相同方式复制相同数据流的协议可能需要这样做。
为了被视为 "典型",CBOR 流必须满足以下要求:
- 整数必须尽可能小。QCborStreamWriter 总是这样做(不需要用户操作,也不可能写入过长的整数)。
- 数组、映射和字符串长度必须尽可能短。如上所述,QCborStreamWriter 会自动这样做。
- 数组、映射和字符串必须使用显式长度。对于字符串,QCborStreamWriter 总是这样做;对于数组和映射,请确保使用显式长度调用startArray() 和startMap() 重载。
- 每个映射中的键必须按升序排序。QCborStreamWriter 在这一项上没有提供任何帮助:开发人员必须在调用append() 映射对之前确保这一点。
- 浮点数值应尽可能小。QCborStreamWriter 不会转换浮点数值;开发人员必须在调用append() 之前进行这一检查(请参阅这些函数的示例)。
严格 CBOR 模式
RFC 7049 第 3.10 节定义了严格模式。与上述 Canonical 编码一样,QCborStreamWriter 可以创建严格的 CBOR 流,但并不要求或验证输出是否如此。
- 映射中的键必须是唯一的。QCborStreamWriter 不会对映射键进行验证。
- 标签可能被要求根据其规范只与正确的类型配对。QCborStreamWriter 不对标签的使用进行验证。
- 文本字符串必须是正确编码的 UTF-8。QCborStreamWriter 总是为使用append() 添加的字符串写入正确的 UTF-8,但不对使用appendTextString() 添加的字符串进行验证。
无效的 CBOR 流
滥用 QCborStreamWriter 也有可能产生无效的 CBOR 流,导致接收器无法解码。以下操作会产生无效数据流:
- 附加标签,但不附加相应的标签值(QCborStreamWriter 不会产生诊断结果)。
- 向具有明确长度的数组或映射表追加过多或过少的项目(endMap() 和endArray() 将返回 false,QCborStreamWriter 将以qWarning() 作为日志)。
{解析和显示 CBOR 数据}、{序列化转换器}、{保存和加载游戏}。
另请参见 QCborStreamReader,QCborValue, 和QXmlStreamWriter 。
成员函数文档
[explicit]
QCborStreamWriter::QCborStreamWriter(QByteArray *data)
创建一个 QCborStreamWriter 对象,将数据流追加到data 。所有数据流都会立即写入字节数组,无需刷新任何缓冲区。
下面的示例将一个数字写入字节数组,然后返回。
QByteArray encodedNumber(qint64 value) { QByteArray ba; QCborStreamWriter writer(&ba); writer.append(value); return ba; }
QCborStreamWriter 不拥有data 的所有权。
[explicit]
QCborStreamWriter::QCborStreamWriter(QIODevice *device)
创建一个 QCborStreamWriter 对象,将数据流写入device 。必须在调用第一个append() 之前打开设备。该构造函数可用于任何派生自QIODevice 的类,如QFile 、QProcess 或QTcpSocket 。
QCborStreamWriter 没有缓冲功能,因此每次调用append() 都会导致一次或多次调用设备的write() 方法。
下面的示例将一个空映射写入文件:
QFile f("output", QIODevice::WriteOnly); QCborStreamWriter writer(&f); writer.startMap(0); writer.endMap();
QCborStreamWriter 不拥有device 的所有权。
[noexcept]
QCborStreamWriter::~QCborStreamWriter()
销毁QCborStreamWriter 对象并释放相关资源。
QCborStreamWriter 不执行错误检查,以确定在销毁对象之前是否已将所有必要项目写入数据流。程序员有责任确保这一点。
void QCborStreamWriter::append(QCborKnownTags tag)
这是一个重载函数。
将 CBOR 标记tag 添加到数据流中,创建一个 CBOR 标记值。所有标记后都必须跟有意义的其他类型。
在下面的示例中,我们将 CBOR 标签 1(Unixtime_t
)和一个代表当前时间的整数(使用time()
函数获取)追加到数据流中:
void writeCurrentTime(QCborStreamWriter &writer) { writer.append(QCborKnownTags::UnixTime_t); writer.append(time(nullptr)); }
另请参见 QCborStreamReader::isTag() 和QCborStreamReader::toTag()。
void QCborStreamWriter::append(QCborNegativeInteger n)
这是一个重载函数。
将 64 位负值n 附加到 CBOR 流中。QCborNegativeInteger 是一个 64 位枚举,用于保存我们要写入的负数的绝对值。如果 n 为零,写入的数值将等于264(即 -18,446,744,073,709,551,616)。
在下面的示例中,我们写入的值是-1、-232和 INT64_MIN:
writer.append(QCborNegativeInteger(1)); writer.append(QCborNegativeInteger(Q_INT64_C(4294967296))); writer.append(QCborNegativeInteger(-quint64(std::numeric_limits<qint64>::min())));
请注意,该函数可用于对无法适合标准计算机 64 位有符号整数(如qint64 )的数字进行编码。也就是说,如果n 大于std::numeric_limits<qint64>::max()
或为 0,这将表示一个小于std::numeric_limits<qint64>::min()
的负数。
另请参见 QCborStreamReader::isNegativeInteger() 和QCborStreamReader::toNegativeInteger()。
void QCborStreamWriter::append(QCborSimpleType st)
这是一个重载函数。
将 CBOR 简单类型st 附加到数据流中,创建一个 CBOR 简单类型值。在下面的示例中,我们编写了 Null 和 32 类型的简单类型,Qt 不支持 32 类型。
writer.append(QCborSimpleType::Null); writer.append(QCborSimpleType(32));
注意: 使用没有规范的简单类型会导致远程接收器出现验证错误。此外,简单类型值 24 至 31(含 31)是保留值,不得使用。
另请参阅 QCborStreamReader::isSimpleType() 和QCborStreamReader::toSimpleType()。
void QCborStreamWriter::append(QCborTag tag)
这是一个重载函数。
将 CBOR 标记tag 添加到数据流中,创建一个 CBOR 标记值。所有标签后都必须有另一种标签类型,它们才有意义。
在下面的示例中,我们将 CBOR 标签 36(正则表达式)和QRegularExpression's 模式追加到数据流中:
void writeRxPattern(QCborStreamWriter &writer, const QRegularExpression &rx) { writer.append(QCborTag(36)); writer.append(rx.pattern()); }
另请参见 QCborStreamReader::isTag() 和QCborStreamReader::toTag()。
void QCborStreamWriter::append(QLatin1StringView str)
这是一个重载函数。
将str 查看到的 Latin-1 字符串追加到数据流中,创建一个 CBOR 文本字符串值。QCborStreamWriter 会尝试将整个字符串写入一个块中。
下面的示例将一个简单的 Latin-1 字面字符串追加到数据流中:
writer.append("Hello, World"_L1);
性能说明:CBOR 要求所有文本字符串都以 UTF-8 编码,因此该函数将遍历字符串中的字符,以确定其内容是否为 US-ASCII。如果发现字符串包含 US-ASCII 以外的字符,它将分配内存并转换为 UTF-8。如果不需要这种检查,请使用appendTextString() 代替。
另请参阅 QCborStreamReader::isString() 和QCborStreamReader::readString()。
void QCborStreamWriter::append(QStringView str)
这是一个重载函数。
将文本字符串str 附加到数据流中,创建一个 CBOR 文本字符串值。QCborStreamWriter 会尝试将整个字符串写入一个数据块中。
下面的示例向数据流写入了一个任意的QString :
void writeString(QCborStreamWriter &writer, const QString &str) { writer.append(str); }
另请参见 QCborStreamReader::isString() 和QCborStreamReader::readString()。
void QCborStreamWriter::append(bool b)
这是一个重载函数。
将布尔值b 附加到数据流中,生成 CBOR False 值或 CBOR True 值。该函数等同于(并以):
writer.append(b ? QCborSimpleType::True : QCborSimpleType::False);
另请参见 appendNull()、appendUndefined()、QCborStreamReader::isBool() 和QCborStreamReader::toBool()。
void QCborStreamWriter::append(const QByteArray &ba)
这是一个重载函数。
将字节数组ba 附加到数据流中,创建一个 CBOR 字节字符串值。QCborStreamWriter 将尝试在一个数据块中写入整个字符串。
下面的示例将加载一个文件的内容并将其追加到数据流中:
void writeFile(QCborStreamWriter &writer, const QString &fileName) { QFile f(fileName); if (f.open(QIODevice::ReadOnly)) writer.append(f.readAll()); }
如示例所示,与 JSON 不同,CBOR 对二进制内容不要求转义。
另请参见 appendByteString()、QCborStreamReader::isByteArray() 和QCborStreamReader::readByteArray()。
void QCborStreamWriter::append(double d)
这是一个重载函数。
它将浮点数d 附加到数据流中,创建一个 CBOR 64 位双精度浮点数值。QCborStreamWriter 总是按原样附加数值,不检查数值是否为 NaN 的规范形式、是否为无穷级、是否为反常或是否可以用更短的格式写入。
下面的代码会执行所有这些检查,除了非正态性检查,因为系统 FPU 或浮点仿真会直接考虑非正态性检查。
void writeDouble(QCborStreamWriter &writer, double d) { float f; if (qIsNaN(d)) { writer.append(qfloat16(qQNaN())); } else if (qIsInf(d)) { writer.append(d < 0 ? -qInf() : qInf()); } else if ((f = d) == d) { qfloat16 f16 = f; if (f16 == f) writer.append(f16); else writer.append(f); } else { writer.append(d); } }
至于如何在不损失精度的情况下将 double 转换为积分,读者可以自行判断。
另请参见 QCborStreamReader::isDouble() 和QCborStreamReader::toDouble()。
void QCborStreamWriter::append(float f)
这是一个重载函数。
将浮点数f 附加到数据流中,创建一个 CBOR 32 位单精度浮点数值。如果没有精度损失,可使用以下代码将 C++double
转换为float
并追加,或者追加double
。
void writeFloat(QCborStreamWriter &writer, double d) { float f = d; if (qIsNaN(d) || d == f) writer.append(f); else writer.append(d); }
另请参见 QCborStreamReader::isFloat() 和QCborStreamReader::toFloat()。
void QCborStreamWriter::append(qfloat16 f)
这是一个重载函数。
将浮点数f 附加到数据流中,创建一个 CBOR 16 位半精度浮点数值。如果没有精度损失,可使用以下代码将 C++float
转换为qfloat16
并追加,或者追加float
。
void writeFloat(QCborStreamWriter &writer, float f) { qfloat16 f16 = f; if (qIsNaN(f) || f16 == f) writer.append(f16); else writer.append(f); }
另请参见 QCborStreamReader::isFloat16() 和QCborStreamReader::toFloat16()。
void QCborStreamWriter::append(qint64 i)
这是一个重载函数。
将 64 位有符号数值i 附加到 CBOR 数据流。这将根据参数的符号创建一个 CBOR 无符号整数或 CBOR 负整数值。在下面的示例中,我们写入了 0、-1、232和INT64_MAX
值:
writer.append(0); writer.append(-1); writer.append(Q_INT64_C(4294967296)); writer.append(std::numeric_limits<qint64>::max());
另请参见 QCborStreamReader::isInteger() 和QCborStreamReader::toInteger()。
void QCborStreamWriter::append(quint64 u)
这是一个重载函数。
将 64 位无符号值u 附加到 CBOR 流,创建一个 CBOR 无符号整数值。在下面的示例中,我们写入了值 0、232和UINT64_MAX
:
writer.append(0U); writer.append(Q_UINT64_C(4294967296)); writer.append(std::numeric_limits<quint64>::max());
另请参阅 QCborStreamReader::isUnsignedInteger() 和QCborStreamReader::toUnsignedInteger()。
void QCborStreamWriter::append(std::nullptr_t)
这是一个重载函数。
在数据流中追加一个 CBOR Null 值。该函数等价于(并以):忽略参数。
writer.append(QCborSimpleType::Null);
另请参阅 appendNull(),append(QCborSimpleType) 和QCborStreamReader::isNull().
void QCborStreamWriter::append(const char *str, qsizetype size = -1)
这是一个重载函数。
将从str 开始的size 字节文本附加到数据流中,创建一个 CBOR 文本字符串值。QCborStreamWriter 将尝试在一个数据块中写入整个字符串。如果size 为-1,该函数将写入strlen(\a str)
字节。
str 指向的字符串应为正确编码的 UTF-8。QCborStreamWriter 不对其进行验证。
另请参阅 append(QLatin1StringView)、append(QStringView)、QCborStreamReader::isString() 和QCborStreamReader::readString()。
void QCborStreamWriter::appendByteString(const char *data, qsizetype len)
将len 字节从data 开始的数据追加到数据流中,创建一个 CBOR 字节字符串值。QCborStreamWriter 将尝试在一个数据块中写入整个字符串。
另请参阅 append()、appendTextString()、QCborStreamReader::isByteArray() 和QCborStreamReader::readByteArray()。
void QCborStreamWriter::appendNull()
将 CBOR Null 值添加到数据流中。该函数等价于(并作为):
writer.append(QCborSimpleType::Null);
另请参阅 append(std::nullptr_t)、append(QCborSimpleType) 和QCborStreamReader::isNull() 。
void QCborStreamWriter::appendTextString(const char *utf8, qsizetype len)
将len 字节从utf8 开始的文本添加到数据流中,创建一个 CBOR 文本字符串值。QCborStreamWriter 将尝试在一个块中写入整个字符串。
utf8 指向的字符串应为正确编码的 UTF-8。QCborStreamWriter 不会验证这一点。
另请参阅 append(QLatin1StringView)、append(QStringView)、QCborStreamReader::isString() 和QCborStreamReader::readString()。
void QCborStreamWriter::appendUndefined()
将一个 CBOR 未定义值添加到数据流中。该函数等同于(并作为):
writer.append(QCborSimpleType::Undefined);
另请参阅 append(QCborSimpleType) 和QCborStreamReader::isUndefined() 。
QIODevice *QCborStreamWriter::device() const
返回QCborStreamWriter 对象正在写入的QIODevice 。该设备必须事先通过构造函数或setDevice() 设置过。
如果此对象是通过写入QByteArray 创建的,则此函数将返回QBuffer 的内部实例,该实例由QCborStreamWriter 拥有。
另请参见 setDevice()。
bool QCborStreamWriter::endArray()
终止由startArray() 的任一重载启动的数组,如果数组中添加的元素数量正确,则返回 true。每次使用startArray() 时都必须调用该函数。
如果返回 false,则表示应用程序出错,并且该数据流中存在不可恢复的错误。如果出现这种情况,QCborStreamWriter 还会使用qWarning() 写入警告。
当当前容器不是数组时调用该函数也是一个错误,不过QCborStreamWriter 目前无法检测到这种情况。
另请参见 startArray()、startArray(quint64) 和endMap()。
bool QCborStreamWriter::endMap()
终止由startMap() 的任一重载启动的映射,如果数组中添加的元素数量正确,则返回 true。每次使用startMap() 时都必须调用该函数。
如果返回 false,则表示应用程序出错,并且该数据流中存在不可恢复的错误。如果出现这种情况,QCborStreamWriter 也会使用qWarning() 写入警告。
当当前容器不是地图时调用该函数也是一个错误,不过QCborStreamWriter 目前无法检测到这种情况。
另请参见 startMap()、startMap(quint64) 和endArray()。
void QCborStreamWriter::setDevice(QIODevice *device)
用device 替换QCborStreamWriter 对象正在写入的设备或字节数组。
另请参见 device()。
void QCborStreamWriter::startArray()
在 CBOR 数据流中启动一个长度不确定的 CBOR 数组。每次调用 startArray() 时必须同时调用endArray() 和当前 CBOR 元素,直到数组结束。
该函数创建的数组没有明确的长度。相反,它的长度由其中包含的元素暗示。但请注意,使用长度不确定的数组不符合规范的 CBOR 编码。
下面的示例追加了输入字符串列表中的元素:
void appendList(QCborStreamWriter &writer, const QList<QString> &values) { writer.startArray(); for (const QString &s : values) writer.append(s); writer.endArray(); }
另请参阅 startArray(quint64)、endArray( )、startMap( )、QCborStreamReader::isArray() 和QCborStreamReader::isLengthKnown() 。
void QCborStreamWriter::startArray(quint64 count)
这是一个重载函数。
在 CBOR 数据流中以count 项的明确长度启动一个 CBOR 数组。每次调用 startArray 时必须同时调用endArray() 和当前 CBOR 元素,直到数组结束。
此函数创建的数组有明确的长度,因此必须将count 项准确地添加到 CBOR 流中。添加较少或较多的项会导致endArray() 失败,CBOR 流也会损坏。不过,规范 CBOR 编码要求数组有明确的长度。
下面的示例追加了输入QStringList 中的所有字符串:
void appendList(QCborStreamWriter &writer, const QStringList &list) { writer.startArray(list.size()); for (const QString &s : list) writer.append(s); writer.endArray(); }
大小限制:此函数的参数为 quint64,似乎允许数组中最多包含264-1 个元素。但是,目前QCborStreamWriter 和QCborStreamReader 在 32 位系统上都限制为232-2 项,在 64 位系统上限制为264-2 项。还请注意,QCborArray 目前在 32 位平台上仅限于227 个元素,在 64 位平台上仅限于259 个元素。
另请参见 startArray()、endArray()、startMap()、QCborStreamReader::isArray() 和QCborStreamReader::isLengthKnown()。
void QCborStreamWriter::startMap()
在 CBOR 流中启动一个长度不确定的 CBOR 地图。每个 startMap() 调用必须与一个endMap() 调用配对,并且当前的 CBOR 元素会一直延伸到映射结束。
该函数创建的映射表没有明确的长度。相反,它的长度是由其中包含的元素暗示的。但请注意,使用长度不确定的映射不符合规范的 CBOR 编码(规范编码还要求键是唯一的,并按排序顺序排列)。
下面的示例从输入的 int 和字符串对列表中追加元素:
void appendMap(QCborStreamWriter &writer, const QList<std::pair<int, QString>> &values) { writer.startMap(); for (const auto pair : values) { writer.append(pair.first) writer.append(pair.second); } writer.endMap(); }
另请参见 startMap(quint64),endMap(),startArray(),QCborStreamReader::isMap() 和QCborStreamReader::isLengthKnown().
void QCborStreamWriter::startMap(quint64 count)
这是一个重载函数。
启动一个 CBOR 映射表,该映射表的长度为count 。每次调用 startMap 时,必须同时调用endMap() 和当前的 CBOR 元素,直到映射结束。
此函数创建的映射具有明确的长度,因此必须向 CBOR 流中添加count 对项。添加较少或较多的项目将导致endMap() 失败,CBOR 流也将损坏。不过,规范 CBOR 编码要求明确长度的映射。
下面的示例追加了输入QMap 中的所有字符串:
void appendMap(QCborStreamWriter &writer, const QMap<int, QString> &map) { writer.startMap(map.size()); for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) { writer.append(it.key()); writer.append(it.value()); } writer.endMap(); }
大小限制:该函数的参数是 quint64,这似乎允许在映射中最多包含264-1 对字符串。然而,目前QCborStreamWriter 和QCborStreamReader 在 32 位系统上只能容纳231-1 个项目,在 64 位系统上只能容纳263-1 个项目。另请注意,QCborMap 目前在 32 位平台上只能容纳226 个元素,在 64 位平台上只能容纳258 个元素。
另请参见 startMap()、endMap()、startArray()、QCborStreamReader::isMap() 和QCborStreamReader::isLengthKnown()。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.