转换数据类型以添加​​到QByteArray以便将原始数据写入文件

时间:2018-10-31 19:03:14

标签: c++ arrays qt file memcpy

我有一些要写入原始数据文件的数据类型。我没有使用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以便将其写入文件的正确方法是什么?

1 个答案:

答案 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);

请记住以下几点:

  1. 数据的字节序很重要。并非所有系统都具有相同的字节序,因此您需要在文档中明确说明字节的定向方式。

  2. 有些人试图通过编写类似float的东西来将uint32_t的位转换为uint32_t rep = *reinterpret_cast<uint32_t*>(&source0);。请勿这样做-这违反了Strict Aliasing Rule

  3. 将版本号序列化为文件的第一部分可能是个好主意,以便将来可以更改数据格式并使它向后兼容。

  4. 许多这种手动位打包可以写入将自动执行的模板函数中。这留给读者练习。

  5. 如果性能很重要,则应在推入之前弄清楚数据的大小和reserve()字节数组中的空间-这样可以节省数组,而不必重新分配和扩展过度。