我正在编写一个应用程序,它应该将一个浮点数组写入WAVE文件。我正在使用QDataStream,但这导致输出非常不可能,我无法解释。看起来QDataStream有时会选择32位浮点数,有时候会选择40位浮点数。这会弄乱整个输出文件,因为它必须服从严格的格式。
我的代码大致如下:
float* array;
unsigned int nSamples;
void saveWAV(const QString& fileName) const
{
QFile outFile(fileName);
if (outFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
QDataStream dataStream(&outFile);
dataStream.setByteOrder(QDataStream::LittleEndian);
dataStream.setFloatingPointPrecision(QDataStream::SinglePrecision);
// ... do all the WAV file header stuff ...
for(int ii = 0; ii < nSamples; ++ii)
dataStream << array[ii];
}
}
我认为没有理由说这个代码会产生这样的副作用。所以我做了一个最小的例子来找出发生了什么。我用这个替换了for循环:
float temp1 = 1.63006e-33f;
float temp2 = 1.55949e-32f;
dataStream << temp1;
dataStream << temp1;
dataStream << temp2;
dataStream << temp1;
dataStream << temp2;
然后我用Matlab打开输出文件,看看写入文件的字节。那些是:
8b 6b 07 09 // this is indeed 1.63006e-33f (notice it's Little Endian)
8b 6b 07 09
5b f2 a1 0d 0a // I don't know what this is but it's a byte to long
8b 6b 07 09
5b f2 a1 0d 0a
我选择了任意值,他们恰好有这种效果。某些值导出为4字节,其他值导出为5字节数字。有谁知道这可能是什么原因?
修改
在检查两个浮点数的大小时,它们看起来确实是4 char
长,但是:
qDebug() << sizeof(temp1); // prints '4'
qDebug() << sizeof(temp2); // prints '4'
答案 0 :(得分:5)
答案在于打开输出文件:QIODevice::Text
标志应该被省略,因为它是一个二进制文件。如果包含text-flag,则在每个0d
之前插入0a
个字符。因此,包含0a
字符的每个浮点数都会因此而延长char
。
此答案的所有学分都会转到以下答案: Length of float changes between 32 and 40 bit
答案 1 :(得分:1)
注意:我不是100%肯定我就在下面,并且很想听到我错了,但这就是我认为的:
QDataStream
有自己的序列化格式,虽然我没有检查,但这可能与此有关。重点是,它并不意味着你要用它做什么:只编写任何二进制格式。您可以使用该类,但我相信您只需要使用writeRawData()
方法,并自己处理字节顺序等。
答案 2 :(得分:1)
即使我没有使用IODevice :: Text标志,我也有类似的问题。我发现添加了一行
dataStream.device()->setTextModeEnabled(false);
解决了问题,以确保您处于二进制模式。