Я пишу приложение, которое должно записать массив с плавающей точкой в файл 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'
Ответ заключается в открытии выходного файла: QIODevice::Text
Флаг должен быть опущен, так как это двоичный файл. Если текстовый флаг включен, 0d
символ вставляется перед каждым 0a
, Таким образом, каждый поплавок, который содержит 0a
персонаж кажется char
дольше из-за этого.
Все кредиты за этот ответ идут на ответы, приведенные в:
Длина плавания изменяется от 32 до 40 бит
Примечание: я не уверен на 100%, что я прямо ниже, и хотел бы услышать, что я не прав, но я так думаю:
QDataStream
имеет свой собственный формат сериализации, и хотя я не проверял, это, вероятно, связано с этим. Дело в том, что оно не предназначено для того, что вы пытаетесь с ним сделать: пишите просто любой двоичный формат. Вы можете использовать класс, но я считаю, что вам нужно использовать только writeRawData()
метод, и сами позаботьтесь о порядке следования байтов.
У меня была похожая проблема, хотя я не использовал флаг IODevice :: Text. Я обнаружил, что добавление строки
dataStream.device()->setTextModeEnabled(false);
решил проблему, чтобы убедиться, что вы находитесь в двоичном режиме.