如何优化Qt C++中24位采样数据的解压与转换耗时?
优化方案
1. 直接操作二进制数据,彻底抛弃字符串转换
原代码通过转十六进制字符串再转整数的方式,是性能瓶颈的核心——字符串拼接、转换会产生大量临时对象和冗余计算。直接读取24位二进制原始数据,完成符号扩展转32位有符号整数:
// 假设数据是大端序(高位字节在前) signed int convertSample(const unsigned char* data) { // 拼接24位数据到32位整数 int32_t sample = (static_cast<int32_t>(data[0]) << 16) | (static_cast<int32_t>(data[1]) << 8) | static_cast<int32_t>(data[2]); // 符号扩展:如果24位的最高位(第23位)为1,说明是负数,需要把32位的高8位设为1 if (sample & 0x800000) { sample |= 0xFF000000; } return sample; } // 如果数据是小端序(低位字节在前),用这个版本 signed int convertSampleLittleEndian(const unsigned char* data) { int32_t sample = (static_cast<int32_t>(data[2]) << 16) | (static_cast<int32_t>(data[1]) << 8) | static_cast<int32_t>(data[0]); if (sample & 0x800000) { sample |= 0xFF000000; } return sample; }
2. 避免循环中频繁创建QByteArray
原代码里chunkSamples.mid(i*3,3)会每次生成新的QByteArray对象,带来不必要的内存分配和拷贝开销。直接通过指针访问chunk的内存:
while(!file.atEnd()){ QByteArray chunkSamples = file.read(chunkSize); const int sampleCount = chunkSamples.size() / 3; // 预分配buffer空间,避免多次扩容拷贝 buffer.reserve(buffer.size() + sampleCount); const unsigned char* ptr = reinterpret_cast<const unsigned char*>(chunkSamples.constData()); for (int i = 0; i < sampleCount ; ++i){ signed int sample = convertSample(ptr + i*3); buffer.append(sample); } }
3. 预分配QVector内存
buffer.append默认会在空间不足时自动扩容,每次扩容都要重新分配内存并拷贝已有数据。提前计算每个chunk的样本数,用reserve预留足够空间,能大幅减少内存操作开销。
4. 增大读取块尺寸(可选)
如果磁盘IO性能允许,适当调大chunkSize(比如从100万样本提升到400万样本),减少文件读取的次数,降低IO层面的开销。注意不要超过可用内存上限。
5. 内存映射文件(可选)
如果使用Qt 5.15及以上版本,可通过QFile::map将整个文件映射到内存,直接访问内存中的数据,彻底避免多次read调用的开销:
QFile file("your_file_path"); if (!file.open(QIODevice::ReadOnly)) { // 处理文件打开错误 } qint64 fileSize = file.size(); const unsigned char* fileData = reinterpret_cast<const unsigned char*>(file.map(0, fileSize)); const int totalSamples = fileSize / 3; buffer.reserve(totalSamples); for (int i = 0; i < totalSamples; ++i) { buffer.append(convertSample(fileData + i*3)); } file.unmap(fileData);
内容的提问来源于stack exchange,提问作者A.A.
相关产品推荐
相关产品推荐

