qt-QDataStream-写入bin文件有多余字符

场景介绍

在这里插入图片描述

结果

在这里插入图片描述

原因分析

在Qt中使用QDataStream写入QByteArray时,QDataStream会默认添加数据长度前缀(4字节的quint32类型),这是其设计行为。具体分析如下:

  1. 文件内容解析
    00 00 00 04:这是QDataStream自动添加的数据长度标识(4字节小端序),表示后续数据长度为4字节(即"aaaa"的长度)。
    61 61 61 61:是字符串"aaaa"的十六进制表示(ASCII码中’a’的十六进制为0x61)。
  2. 根本原因
    QDataStream是一个二进制序列化流,默认会为动态数据(如QByteArray、QString)添加长度前缀,以确保数据读取时能正确解析边界。这种设计适用于需要跨平台/跨版本兼容性的场景,但会引入额外字节。
  3. 解决方案
    如果需要直接写入原始字节(无长度前缀),避免使用QDataStream,改用QFile的write()方法:
QString dir_str = QApplication::applicationDirPath() + "/ExcelOut/Bin";
QString fileBasicName = dir_str + "/test";
QFile file(fileBasicName);
if(file.open(QIODevice::WriteOnly | QIODevice::Append)) {
    QByteArray byte = "aaaa";
    file.write(byte);  // 直接写入原始字节
    file.close();
}
  1. 若必须使用QDataStream
    可通过调整流格式减少额外字节,但无法完全消除长度前缀(除非手动控制):
QDataStream stream(&file);
stream.setVersion(QDataStream::Qt_5_15);  // 明确版本
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
stream.setByteOrder(QDataStream::LittleEndian);
// 写入时仍会包含长度前缀
stream << byte;
  1. 关键区别
  • QFile::write():直接写入原始字节,无任何附加信息。
  • QDataStream::operator<<:为数据添加类型/长度元信息,适用于结构化数据存储。

验证建议
使用十六进制编辑器查看文件时,确认是否仅存在00 00 00 04 + 61 61 61 61,无其他隐藏字符。若需严格二进制兼容,优先使用QFile::write()。

<think>我们使用Qt的QFile类来写入二进制文件。步骤如下: 1. 创建QFile对象并打开文件,指定打开模式为写入(QIODevice::WriteOnly)和二进制模式(QIODevice::Binary)。注意:默认情况下QFile是二进制模式,但为了清晰可以显式指定。 2. 使用QDataStream来辅助写入,它可以方便地写入各种数据类型。 3. 将参数按照需要的格式写入QDataStream。 4. 关闭文件。 注意:写入二进制文件时,需要确保写入的数据类型和顺序与读取时完全一致,否则读取会出错。 以下是一个示例代码,假设我们要写入一些参数:一个整数版本号,一个浮点数(golden_f0),以及三个整数(low_map_freq, high_map_freq, 和一个字节的flag)。 ```cpp #include <QFile> #include <QDataStream> #include <QDebug> bool writeParamsToBin(const QString& filename, quint8 version, float golden_f0, quint16 low_map_freq, quint16 high_map_freq, quint8 flag) { QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Binary)) { qDebug() << "Cannot open file for writing:" << file.errorString(); return false; } QDataStream out(&file); // 设置数据流的版本,以确保跨平台兼容性(根据需要设置) out.setVersion(QDataStream::Qt_5_15); // 写入数据,注意顺序 out << version; out << golden_f0; out << low_map_freq; out << high_map_freq; out << flag; file.close(); return true; } ``` 调用示例: ```cpp int main() { QString binFile = "params.bin"; quint8 version = 0x01; float golden_f0 = 170.0f; // 170Hz quint16 low_map_freq = 120; // 120Hz quint16 high_map_freq = 220; // 220Hz quint8 flag = 0x00; if (writeParamsToBin(binFile, version, golden_f0, low_map_freq, high_map_freq, flag)) { qDebug() << "Parameters written successfully."; } else { qDebug() << "Failed to write parameters."; } return 0; } ``` 注意事项: - 使用QDataStream写入时,它会自动处理字节序(默认是大端序,但我们可以设置)。如果需要在不同平台之间共享数据,需要注意字节序问题。可以通过`out.setByteOrder(QDataStream::LittleEndian);`来设置为小端序(Intel处理器通常是小端序)。 - 写入的数据类型必须与读取时一致。例如,写入quint8(无符号8位整数)和quint16(无符号16位整数)等。 引用中提到,默认情况下QFile是二进制模式,不会进行任何转换,所以我们直接使用即可。 另外,如果参数结构复杂,可以考虑使用结构体,然后一次性写入整个结构体(但要注意结构体内存对齐问题,通常不建议直接写入结构体,而是逐个成员写入)。 §§相关问题§§ 1. 如何用Qt从二进制文件中读取参数? 2. 在Qt中处理二进制文件时如何确保跨平台兼容性(如字节序)? 3. 如何将结构体数据写入二进制文件? 4. 如果参数中包含字符串,该如何写入二进制文件?</think>### C++ QT Windows 写入参数到bin文件的方法 在Windows系统中使用Qt写入二进制文件(.bin)的步骤如下: #### 1. **创建并打开文件** ```cpp QFile binFile("parameters.bin"); if (!binFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qDebug() << "文件打开失败:" << binFile.errorString(); return; } ``` - `QIODevice::WriteOnly`:只写模式 - `QIODevice::Truncate`:清空现有内容(可选) - **注意**:Qt默认以二进制模式处理文件,无需额外标志[^1] #### 2. **写入二进制数据** ```cpp // 准备参数数据(示例) const char version = 0x01; // 版本号 const float golden_f0 = 170.0f; // 浮点参数 const quint16 freq_params[] = {120, 220}; // 整型数组 // 创建数据流 QDataStream out(&binFile); out.setByteOrder(QDataStream::LittleEndian); // 设置字节序(Windows通常小端) // 写入数据 out << version; out << golden_f0; out.writeRawData(reinterpret_cast<const char*>(freq_params), sizeof(freq_params)); ``` #### 3. **关闭文件** ```cpp binFile.close(); // 确保数据写入磁盘 ``` #### 完整示例代码 ```cpp #include <QFile> #include <QDataStream> #include <QDebug> void writeBinFile() { // 1. 打开文件 QFile file("config.bin"); if (!file.open(QIODevice::WriteOnly)) { qWarning("无法创建文件"); return; } // 2. 写入二进制数据 QDataStream stream(&file); stream.setVersion(QDataStream::Qt_5_15); // 设置流版本 // 写入参数 quint8 header[4] = {0x01, 0x01, 0x09, 0x26}; // 文件头 float golden_f0 = 170.0f; // 浮点数 quint16 frequencies[2] = {120, 220}; // 数组参数 stream.writeRawData(reinterpret_cast<char*>(header), sizeof(header)); stream << golden_f0; stream.writeRawData(reinterpret_cast<char*>(frequencies), sizeof(frequencies)); // 3. 关闭文件 file.close(); qDebug() << "参数已写入bin文件"; } ``` ### 关键注意事项 1. **字节序处理**: - Windows系统使用小端序(Little-Endian) - 使用`setByteOrder(QDataStream::LittleEndian)`显式声明 - 跨平台时需考虑目标系统字节序 2. **数据类型对齐**: - 结构体参数建议使用`#pragma pack(1)`取消对齐 - 或手动序列化每个字段 3. **错误处理**: ```cpp if (stream.status() != QDataStream::Ok) { qDebug() << "写入错误:" << stream.status(); } ``` 4. **性能优化**: - 批量写入数据减少I/O操作 - 使用`QBuffer`内存缓存加速小文件操作 ### 验证写入结果 可使用十六进制编辑器检查文件内容,例如用VS Code的Hex Editor插件查看: ``` 00000000: 01 01 09 26 00 00 2A 43 78 00 DC 00 ...*..Cx... ``` 对应: - `01 01 09 26` → 文件头[^4] - `00 00 2A 43` → 170.0f (十六进制42AA0000小端表示) - `78 00` → 120(0x0078) - `DC 00` → 220(0x00DC)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世转神风-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值