我有一些要写入原始数据文件的数据类型。我没有使用QDataStream,因为这会写一些有关数据的额外信息,例如数据的长度和顺序。我只想要一个仅是我写入的字节的文件,并且只能由知道所写入数据类型的正确顺序和大小的人来解释。
我正在使用QFile,其写入方法为qint64 QIODevice::write(const QByteArray &byteArray)
。
我有一些uint8_t,uint32_t,并且浮点型写入文件。如何将这些数据转换为没有额外字节的QByteArray?
这是我到目前为止所拥有的:
void FileWriter::writeData(uint8_t status, uint8_t channel, uint32_t ticks, float source0, float source1){
QByteArray dataToWrite;
//some code to add the paramters to the dataToWrite array
this->file.write(dataToWrite);
}
强制转换为char
的常规旧样式会给我一个implicit conversion changes signedness
错误,因此无法正确存储该值。
将这些值复制到QByteArray以便将其写入文件的正确方法是什么?
答案 0 :(得分:1)
通常,您要序列化数据流,同时注意数据的字节序。
uint8_t
变量可以通过简单的static_cast
转换为字节。对于较大的整数类型,您需要跟踪数据的字节序,并将其逐字节推入。
float
数据类型有些棘手。您首先需要将浮点数的位表示为整数值(uint32_t
),然后从那里进行序列化。一个示例如下所示:
QByteArray data;
//serialize a uint8_t
data.push_back(static_cast<char>(status));
//serialize a uint32_t, little-endian
data.push_back(static_cast<char>((ticks) & 0xFF); //lowest-order byte
data.push_back(static_cast<char>((ticks >> 8) & 0xFF));
data.push_back(static_cast<char>((ticks >> 16) & 0xFF));
data.push_back(static_cast<char>((ticks >> 24) & 0xFF)); //highest-order byte
//serialize a float, by first representing the bits as a uint32_t:
static_assert(sizeof(float) == sizeof(uint32_t), "Floats should be 4 bytes");
uint32_t rep;
std::memcpy(&rep, &source0, sizeof(float)); //using memcpy here so that we don't violate strict aliasing.
data.push_back(static_cast<char>((rep) & 0xFF);
data.push_back(static_cast<char>((rep >> 8) & 0xFF));
data.push_back(static_cast<char>((rep >> 16) & 0xFF));
data.push_back(static_cast<char>((rep >> 24) & 0xFF));
this->file.write(data);
请记住以下几点:
数据的字节序很重要。并非所有系统都具有相同的字节序,因此您需要在文档中明确说明字节的定向方式。
有些人试图通过编写类似float
的东西来将uint32_t
的位转换为uint32_t rep = *reinterpret_cast<uint32_t*>(&source0);
。请勿这样做-这违反了Strict Aliasing Rule。
将版本号序列化为文件的第一部分可能是个好主意,以便将来可以更改数据格式并使它向后兼容。
许多这种手动位打包可以写入将自动执行的模板函数中。这留给读者练习。
如果性能很重要,则应在推入之前弄清楚数据的大小和reserve()
字节数组中的空间-这样可以节省数组,而不必重新分配和扩展过度。