C++ 将数据类型转换为添加到QByteArray以将原始数据写入文件

C++ 将数据类型转换为添加到QByteArray以将原始数据写入文件,c++,qt,file,serialization,memcpy,C++,Qt,File,Serialization,Memcpy,我有一些试图写入原始数据文件的数据类型。我没有使用QDataStream,因为它会写入一些关于数据的额外信息,比如数据的长度和顺序。我只是想要一个只有我写的字节的文件,并且只能由知道所写数据类型的正确顺序和大小的人来解释 我使用的是QFile,其写入方法是qint64 QIODevice::write(constqbytearray&byteArray) 我有一些uint8\u t、uint32\u t和float要写入文件。如何将此数据转换为QByteArray,而无需额外的字节 以下是我到目

我有一些试图写入原始数据文件的数据类型。我没有使用QDataStream,因为它会写入一些关于数据的额外信息,比如数据的长度和顺序。我只是想要一个只有我写的字节的文件,并且只能由知道所写数据类型的正确顺序和大小的人来解释

我使用的是QFile,其写入方法是
qint64 QIODevice::write(constqbytearray&byteArray)

我有一些uint8\u t、uint32\u t和float要写入文件。如何将此数据转换为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
进行常规旧式转换时,会出现
隐式转换更改签名的错误,因此无法正确存储值


将这些值复制到QByteArray以便将其写入文件的正确方法是什么?

通常,您希望序列化数据流,同时注意数据的结尾

uint8\u t
变量可以通过简单的
static\u cast
转换为字节。对于较大的整数类型,您需要跟踪数据的endianness,并逐字节推送数据

float
数据类型有点棘手。首先需要将浮点的位表示为整数值(
uint32\u 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);
QByteArray数据;
//序列化uint8\t
数据。推回(静态施法(状态));
//序列化uint32_t,小端点
data.push_back(static_cast((ticks)&0xFF);//最低顺序字节
数据。推回(静态转换((滴答声>>8)和0xFF));
数据。推回(静态转换((滴答声>>16)和0xFF));
data.push_back(静态_cast((ticks>>24)&0xFF));//最高顺序字节
//通过首先将位表示为uint32\t来序列化浮点:
静态断言(sizeof(float)=sizeof(uint32_t),“float应该是4个字节”);
uint32_t代表;
std::memcpy(&rep,&source0,sizeof(float));//在这里使用memcpy,这样我们就不会违反严格的别名。
数据。推回(静态转换((rep)和0xFF);
数据。推回(静态转换((rep>>8)和0xFF));
数据。推回(静态转换((rep>>16)和0xFF));
数据。推回(静态转换((rep>>24)和0xFF));
此->文件.写入(数据);
需要记住的几件事:

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

  • 有些人试图通过编写类似于
    uint32\u t rep=*reinterpret\u cast(&source0);
    的内容,将
    float
    的位转换为
    uint32\u t

  • 最好将版本号序列化为文件的第一部分,以便将来可以对数据格式进行更改并使其向后兼容

  • 很多这种手动位打包都可以写入模板函数,这些函数将自动完成。这将留给读者作为练习

  • 如果性能很重要,那么在推送之前,您应该计算出数据的大小以及字节数组中的空间大小,这样可以避免数组不得不重新分配和不断增长


  • 通常,您希望序列化数据流,同时注意数据的结尾

    uint8\u t
    变量可以通过简单的
    static\u cast
    转换为字节。对于较大的整数类型,您需要跟踪数据的尾数,并逐字节推送数据

    float
    数据类型有点复杂。首先需要将浮点的位表示为整数值(
    uint32\u 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);
    
    QByteArray数据;
    //序列化uint8\t
    数据。推回(静态施法(状态));
    //序列化uint32_t,小端点
    data.push_back(static_cast((ticks)&0xFF);//最低顺序字节
    数据。推回(静态转换((滴答声>>8)和0xFF));
    数据。推回(静态转换((滴答声>>16)和0xFF));
    data.push_back(静态_cast((ticks>>24)&0xFF));//最高顺序字节
    //通过首先将位表示为uint32\t来序列化浮点:
    静态断言(sizeof(float)=sizeof(uint32_t),“float应该是4个字节”);
    uint32_t代表;
    std::memcpy(&rep,&source0,sizeof(float));//在这里使用memcpy,这样我们就不会违反严格的别名。
    数据。推回(静态转换((rep)和0xFF);
    数据。推回(静态转换((rep>>8)和0xFF));
    数据。推回(静态转换((rep>>16)和0xFF));
    数据。推回(静态转换((rep>>24)和0xFF));
    此->文件.写入(数据);
    
    需要记住的几件事:

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

  • 有些人试图通过编写类似于
    uint32\u t rep=*reinterpret\u cast(&source0);
    的内容,将
    float
    的位转换为
    uint32\u t

  • 最好将版本号序列化为文件的第一部分,以便将来可以对数据格式进行更改并使其向后兼容

  • 很多这种手动位打包都可以写入模板函数,这些函数将自动完成。这将留给读者作为练习

  • 如果性能很重要,那么在推送之前,您应该计算出数据的大小以及字节数组中的空间大小,这样可以避免数组不得不重新分配和不断增长


  • 谢谢。到目前为止,应用程序将只在一个平台上运行,因此endianness现在不是非常重要。这是perfec