我正在编写一个二进制I / O,用于在我的应用程序中存储数据。
为了说明,请考虑我要将大小为10的双数组存储到文件。
现在由于不能保证double在所有平台上都使用8个字节,因此需要对文件的读者进行一些修改。 虽然我使用的是Qt,但我认为问题主要在于将char *中读取的数据转换为double的方式。读取的数据几乎为零。
例如,1读作2.08607954259741e-317。
为什么即使不是每个双读都被读为零?
void FileString::SaveBinary()
{
QFile *file = new QFile(fileName);
if (!file->open(QFile::WriteOnly))
{
QString err = file->errorString();
QString *msgText = new QString("Could not open the file from disk!\n");
msgText->append(err);
QString *msgTitle = new QString("ERROR: Could not open the file!");
emit errMsg(msgTitle, msgText, "WARNING");
delete file;
return;
}
QDataStream out(file);
QString line = "MyApp";
out << line;
line.setNum(size);//size = 10
out << line;
line.setNum(sizeof(double));
out << line;
for(int i = 0; i < size; i++)
{
out << array[i];
}
if(out.status() != QDataStream::Ok)
{
qCritical("error: " + QString::number(out.status()).toAscii());
}
file->close();
delete file;
}
void FileString::ReadBinary()
{
bool ok = false;
QString line = "";
QFile *file = new QFile(fileName);
if (!file->open(QFile::ReadOnly))
{
QString err = file->errorString();
QString *msgText = new QString("Could not open the file from disk!\n");
msgText->append(err);
QString *msgTitle = new QString("ERROR: Could not open the file!");
emit errMsg(msgTitle, msgText, "WARNING");
delete file;
return;
}
QDataStream in(file);
in >> line;
if(line.simplified().contains("MyApp"))
{
in >> line;
size = line.simplified().toInt();
if(size == 10)
{
int mysize = 0;
in >> line;
mysize = line.simplified().toInt();
if(1)//this block runs perfect
{
for(int i = 0; i < size; i++)
{
in >> array[i];
}
if(in.status() == QDataStream::Ok)
ok = true;
}
}
else if(1)//this block reads only zeros
{
char *reader = new char[mysize + 1];
int read = 0;
double *dptr = NULL;
for(int i = 0; i < size; i++)
{
read = in.readRawData(reader, mysize);
if(read != mysize)
{
break;
}
dptr = reinterpret_cast<double *>(reader);//garbage data stored in dptr, why?
if(dptr)
{
array[i] = *dptr;
dptr = NULL;
}
else
{
break;
}
}
if(in.status() == QDataStream::Ok)
ok = true;
delete[] reader;
}
}
}
if(!ok || (in.status() != QDataStream::Ok))
{
qCritical("error : true" + " status = " + QString::number((int) in.status()).toAscii());
}
file->close();
delete file;
}
编辑:
生成的文件的内容
& M y A p p 1 . 1 8 . 3 . 0 1 0 8?ð @ @ @ @ @ @ @ @" @$
应该包含:
MyApp 1.18.3.010812345678910
"MyApp 1.18.3.0" "10" "8" "12345678910"
答案 0 :(得分:1)
如果读取平台上的sizeof double
与写入平台上的sizeof double
不同,您希望阅读什么?
假设您的写平台上的sizeof double
为10.然后您将一个10字节的序列存储在一个代表10字节双精度的文件中。然后,如果读取平台上的sizeof double
是8,那么您将尝试将10字节双精度的位解析为8字节,这显然会导致垃圾。
这是一个更直观的例子:
如果你有一个2字节的整数,比如5.如果你把它存储在二进制文件中,你将得到一个2字节的序列:00000000 00000101
。然后,如果你尝试读取与1字节int相同的数字,你将设法只读取第一个字节,即00000000
,结果只得到零。
考虑使用字符串来保存可移植性的双精度https://stackoverflow.com/a/6790009/817441
答案 1 :(得分:1)
请注意,在原始代码中,sizeof(double)可以使用而不是硬编码字符串,但只要迁移到具有不同双倍大小的不同体系结构,就不会这样。
作为旁注,如果您担心双字符串到字符串转换的性能,那么当您的用户或您希望稍后迁移到嵌入时,可能会遇到更多问题。我刚刚在一个循环中运行了一些转换,而且在我的旧笔记本电脑上也没那么糟糕。这是我非常糟糕的基准测试结果:
time ./main
real 0m1.244s
user 0m1.240s
sys 0m0.000s
我想再次指出它是一台旧笔记本电脑。
代码:
#include <QString>
int main()
{
for (int i = 0; i < 1000000; ++i)
QString::number(5.123456789012345, 'g', 15);
return 0;
}
因此,我建议使用以下方法代替非便携式直接写入:
QString QString :: number(double n,char format ='g',int precision = 6)[静态]
返回等价于n的字符串,根据指定的格式和精度进行格式化。有关详细信息,请参阅参数格式。
与QLocale :: toString()不同,此函数不支持用户的语言环境设置。
http://doc-snapshot.qt-project.org/qdoc/qstring.html#number-2
在讨论了所有这些之后,如果我是你,我会写这样的东西:
void FileString::SaveBinary()
{
QFile *file = new QFile(fileName);
if (!file->open(QFile::WriteOnly))
{
QString err = file->errorString();
QString *msgText = new QString("Could not open the file from disk!\n");
msgText->append(err);
QString *msgTitle = new QString("ERROR: Could not open the file!");
emit errMsg(msgTitle, msgText, "WARNING");
delete file;
return;
}
QDataStream out(file);
QString line = QString::number(myDouble);
out << line;
for(int i = 0; i < size; i++)
{
out << array[i];
}
if(out.status() != QDataStream::Ok)
{
qCritical("error: " + QString::number(out.status()).toAscii());
}
file->close();
delete file;
}
一个便携式选项可能是使用long double,但当然这会增加其他地方的计算,因此根据场景,它可能是也可能不是一种选择。