我在c ++函数中遇到了这个指针的麻烦。 我会把我的类写成二进制文件,所以我写这个函数成员
void Product::saveProducts(){
fstream file;
Product temp;
temp.setId(-1);
bool flag = false;
file.open("cigarettes.dat", ios::out | ios::binary);
if(file.is_open()){
file.seekg(0, ios::end);
if(file.tellg()!=0){
file.seekg(0, ios::beg);
while(!file.eof()){
file.read(reinterpret_cast<char *>(&temp), sizeof(temp));
if(temp.getId() == this->getId()){
flag=true;
file.seekp(-sizeof(temp),ios::cur);
file.write(reinterpret_cast<char *>(this), sizeof(temp));
break;
}
}
}
if(!flag){
file.write(reinterpret_cast<char *>(this), sizeof(temp));
}
}
file.flush();
file.close();
}
但是当我尝试用另一个函数成员检索我的存储对象时:
list<Product> Product::loadProducsts(){
fstream file;
Product temp;
list<Product> products;
file.open("cigarettes.dat", ios::in | ios::binary);
if(file.is_open()){
while(!file.eof()){
file.read(reinterpret_cast<char *>(&temp), sizeof(temp));
products.push_front(temp);
}
}
file.close();
return products;
}
我的数组只填充了一个空对象。问题是什么?
答案 0 :(得分:2)
您的代码存在任何问题,首先是
只是将位转储到文件的事实通常不会
给你一些有用的东西,你可以回读。这个事实
你需要一个reinterpret_cast
才能使用它应该给你提示
关闭。另外:
您只打开文件输出,然后尝试从中读取 它。 (打开输出文件会截断它,所以你已经 丢失了以前的所有数据。)
我不确定您对while (!file.eof())
的看法,
但这肯定不正确。如果由于某种原因,
file.read
失败但未触及文件末尾,您将结束
例如,在无限循环中。
您正在使用file.read
的结果而不进行验证
该功能有效。
关闭文件而不是结束。这会截断 文件以输出模式打开。
第二个片段的读取循环中的相同问题。如果
文件是空的,你仍然会“读取”一个对象,推动
默认构建temp
到products
。
不知道Product
的样子,也不知道初始内容
该文件,很难说真正发生了什么。但
最有可能的是:
您使用open截断文件。它现在有一个长度 0
由于file.tellg()
返回0
,您甚至都不会尝试阅读
它。 (如果您尝试阅读它,则会设置错误,
这将使所有连续的操作无操作。)
然后编写单个元素,并关闭文件。
我唯一不太确定的是:在这种情况下,文件
实际上确实包含一个元素。所以当你试着读它时
第一个file.read
成功,可能没有设置
eofbit
,因为file.read
不需要任何展望。而如果
eofbit
未设置,我希望你第二次循环,
并将temp
中未修改的位推入products
秒
时间。
编辑:
FWIW: if 我们假设您处于非常有限的情况
只是将数据位写入磁盘是有效的(哪个
通常意味着你将在以后重新阅读它们
过程,但从来没有从不同的过程),和那个
有效id
中Product
永远不能为-1,你可能是什么
我想做的是:
Product temp;
temp.setId( -1 ); // This sort of thing should really be handled by a constructor
std::fstream file( "cigartettes.dat", ios::out | ios::in | ios::binary );
while ( file.read( reinterpret_cast<char*>( &temp ), sizeof(temp) && temp.getId() != getId() ) {
}
if ( file.gcount() != 0 ) {
// Error somewhere, we ended up reading a partial record
} else if ( temp.getId() == getId() ) {
file.seekp( -static_cast<int>( sizeof(temp) ) );
} else {
file.clear();
file.flush();
}
file.write( reinterpret_cast<char const*>( this ), sizeof(*this) );
file.close();
if ( !file ) {
// Something went wrong somewhere...
}
几条评论:
需要打开输入和输出。仅开放 输出意味着1)文件将被截断,2)任何 尝试阅读它会失败。
file.read
无法读取正确的数字,则会失败
字节。如果它失败了,可能已经读取了一些字节(和
覆盖了Product
中的id字段,并保留了当前字段
指针在某个位置,而不是对象的模数
尺寸)。所以你应该使用来自的值检查这个
file.gcount()
(返回由...读取的字节数
最后一次未格式化的读操作 - 在读取的情况下
你正在做,这只能与sizeof(Product)
不同
如果读取失败。
指定负值以向后搜索时:您有
在做之前将sizeof
的结果转换为签名类型
-
。否则,你最终会得到一些天文数字
正值,这将导致你试图寻求超越
文件结尾(将失败)。
当读取失败,并且读取的字节数为0时,您就是
到了文件的末尾。然后设置failbit
导致所有未来的操作失败。所以我们必须清除
如果我们要编写扩展数据的错误。 (要是我们
没有达到档案的结尾,当然,没有什么可以做的
清楚的。)
进行双向输入时,读取后必须执行 在写入之前寻求或冲洗。 (不要问我为什么; 这正是标准所说的。)
最后,最好验证文件的状态 在关闭之后,当所有缓冲区都已完全刷新并且 传递给操作系统。如果由于某种原因,写入失败 在某个地方,你想知道它,通知用户 输出的文件已损坏。
我可能会补充说,通常只修改一条记录 文件是将文件复制到新文件,替换或附加 更改记录,然后删除旧文件并重命名 新。尝试修改文件,正如您所做的那样,可能意味着 如果出现问题,你会丢失所有数据。