在C++中读取二进制文件时将char*转换为double
Converting char * to double while reading from binary file in C++?
我正在编写一个二进制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"
如果读取平台上的sizeof double
与写入平台上的sizeof double
不同,您希望读取什么?
假设您的写作平台上的sizeof double
是10。然后,您将一个10字节的序列存储在一个表示10字节双字节的文件中。然后,如果您的读取平台上的sizeof double
是8,那么您将尝试将10字节的双字节的位解析为8字节,这显然会以垃圾告终。
下面是一个更直观的int示例:如果你有一个2字节的整数,比如5。如果您将其存储在二进制文件中,您将得到一个2字节的序列:00000000 00000101
。然后,如果你试图读取与1字节int相同的数字,你将设法只读取第一个字节,即00000000
,结果只得到零。
考虑使用字符串保存替身以便于移植https://stackoverflow.com/a/6790009/817441
请注意,在您的原始代码中,sizeof(double)可以代替硬编码字符串,但它不会迁移到具有不同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::数字(双n,字符格式='g',int精度=6)[static]
返回一个相当于数字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;
}
一个可移植的选项可以是使用长double,但这当然会增加其他地方的计算量,因此根据场景的不同,它可能是一个选项,也可能不是一个选项。
- 将无符号char*转换为std::istream*C++
- 为什么这个函数将"const char*"转换为"void* const"而不是"const void*"
- 将函数参数"const char*"转换为"std::string_view"是
- C ++如何在使用"tolower"时将char转换为int
- 有没有办法在C++的赋值中将"char**"转换为"double"?
- JavaCPP 错误:无法将参数"1"的"char*"转换为"Abc*
- 为什么从 char 转换为 std::byte 可能是未定义的行为?
- 如何在虚幻引擎4中将char*转换为TCHAR?
- C++:将模板类型 char 转换为 std::string
- strcmp/char* 转换无法按预期工作
- C++中的SQLite char*转换
- 无法从 const char* 转换为 const char *&
- 在 C++ 中将 char 转换为 int,而无需符号位传播
- 如果必须包含西里尔字符,如何将 char* 转换为 std::string?
- 试图使用strCMP时的char转换错误
- 无法从'const char *'转换为'LPCTSTR'
- 将 std::vector<char> 转换为字符* 会导致字符缺陷
- 使用 static_cast 将 char 转换为 int c++
- 如何在 C++(MFC) 中将 char* 转换为 LPCTSTR
- 无法将const char转换为字符串构造字符串