我正在尝试制作一个程序,该程序可以将数据读写到数据文件中。由于某种原因,我无法弄清楚,它无法仅从名称和数字名称中读取文件中的字符。我需要字符,以便显示项目列表。
文件中的数据是记录,结构是这个,尝试获取char时发生错误。
struct Data
{
char Genre;
string Productname;
int Numberofproducts;
int Numberofproductsleft;
int Numberofproductssold;
bool Morethantwo;
bool Noticeseen;
float price;
};
//Lists genre to choose from
string listofgenres[] = {"1) Book", "2) Movie", "3) Other", "4) Delete Entry" };
这是我命名为输入的void函数内部的代码,该数据将数据写入文件。这是一本书,还有其他三个选项,这就是为什么它们有一个字符来标识数据类型的原因。
Data put;
int choice;
string genrechosen;
ofstream F;
int count = 0;
cout<<"What genre is the item? (Type the option or enter 1,2, or 3): "<<endl;
while(count < logs)
{
cout<<listofgenres[count]<<endl;
count++;
}
cin >> genrechosen;
genrechosen = validate(genrechosen, 'I');
if(genrechosen == "1" || genrechosen == "Books" || genrechosen == "books" || genrechosen == "Book" || genrechosen == "book" || genrechosen == "B" || genrechosen == "b")
{
F.open(filename, ios::out|ios::app|ios::binary);
put.Genre = '~';
cout<<"What is the name of the book: "<<endl;
cin >> put.Productname;
cout<<"How many "<<put.Productname<<" do you have: "<<endl;
cin >> put.Numberofproducts;
neg(put.Numberofproducts);
cout<<"How much are you selling "<<put.Productname<<" for? (If you don't know , just put 0. Don't put a $): "<<endl;
cin >> put.price;
neg(put.price);
put.Numberofproductssold = 0;
put.Numberofproductsleft = put.Numberofproducts;
if(put.Numberofproducts >= 2)
put.Morethantwo = true;
else
put.Morethantwo = false;
put.Noticeseen = false;
F.write( (const char *)&put , sizeof(put));
F.close();
}
我用过reinterpret_cast,但失败了,这就是为什么F.write就是这样。
尝试从文件中读取数据时出现错误(在我称为Modify的void函数中),我也尝试仅使用常规文本文件仍然遇到相同的问题。
Data change;
string answer;
char genrechosen;
int sold;
int continuee;
int continued;
int passedrecords = 0;
vector <int> position;
f1.open(filename, ios::in|ios::out|ios::ate|ios::binary);
int count = 1;
cout<<"What genre is the item you are looking for? "<<endl;
for(int val = 0; val <= logs; val++)
cout<<listofgenres[val]<<endl;
cin >> answer;
//Validates input
if(answer != "4" || answer != "Delete Entry" || answer != "delete entry" || answer != "Delete" || answer != "delete" || answer != "D" || answer != "d" )
answer = validate(answer, 'I'); // Uses I for the char variable because they both use same list, so there is no point in creating new char for it.
//Allows for list of only that genre to be shown
else if(answer == "1" || answer == "Books" || answer == "books" || answer == "Book" || answer == "book" || answer == "B" || answer == "b")
genrechosen = '~';
else if(answer == "2" || answer == "Movies" || answer == "movies" || answer == "Movie" || answer == "movie" || answer == "M" || answer == "m")
genrechosen = '!';
else if(answer == "3" || answer == "Other" || answer == "other" || answer == "O" || answer == "o")
genrechosen = '@';
else
genrechosen = '_';
//Displays List of items in that genre
if(genrechosen == bs)
cout<<"Which book's data will you be modifying? (Type in the number):"<<endl;
if(genrechosen == ms)
cout<<"Which movie's data will you be modifying? (Type in the number):"<<endl;
if(genrechosen == orr)
cout<<"What item's data will you be modifying? (Type in the number):"<<endl;
if(genrechosen == de)
{
deleterec();
return;
}
//Read records until eof
while( f1.read( (char *)&change, sizeof(change)) )
{
if(change.Genre == genrechosen)
{
cout<<count<<") "<<change.Productname<<endl;
count++;
position.push_back(passedrecords);
}
(Personal comment)/* We need to know exactly what record in the file matches that genre, that way when the users chooses a number of the list, we can go and find
that exact record. We don't want only 2 records to show up and then conclude the user wants the second record when they actually want the 37th record.*/
passedrecords++;
}
Tl; Dr;
问题是,当有多个记录时,while循环仅迭代一次。也请更改。流派永远不会有实际值,因此不会显示任何记录。我无法读取名称或char数据,只能读取double / integers。我正在阅读的C ++书说对不同的数据类型使用二进制文件,是吗?谢谢,很抱歉。我正在使用代码块编译器顺便说一句。
编辑1:一次编写一个结构后,我遇到了这个错误:
f1.read( (char *)&change.Genre, sizeof(change.Genre));
uint32_t size = change.Productname.length();
f1.read( (char *)&size, sizeof(size));
f1.read( change.Productname.data() , size); //Problematic Line
f1.read( (const char *)&change.Numberofproducts, sizeof(change.Numberofproducts));
f1.read( ( const char *)&change.Numberofproductsleft, sizeof(change.Numberofproductsleft));
f1.read( ( const char *)&change.Numberofproductssold, sizeof(change.Numberofproductssold));
f1.read( ( const char *)&change.Morethantwo, sizeof(change.Morethantwo));
f1.read( ( const char *)&change.Noticeseen, sizeof(change.Noticeseen));
f1.read( ( const char *)&change.price, sizeof(change.price));
给我错误“从const char到char的无效转换”。
答案 0 :(得分:2)
String不能用fwrite
编写,以便以后进行安全重构。
快速修复(通常不建议)是替换:
string Productname;
使用
char Productname[100];
或者更好的是一次写一个字段。字符串字段可以写为大小+字符,如下所示:
F.write( (const char *)&put.Genre, sizeof(put.Genre));
uint32_t size = put.Productname.length();
F.write( (const char *)&size, sizeof(size));
F.write(put.Productname.data(), size);
F.write( (const char *)&put.Numberofproducts, sizeof(put.Numberofproducts));
//... and so on
阅读应该以相同的方式进行。
注意:在文件中读写对象的过程通常称为序列化和反序列化。例如boost serialization。
注意2:为了文件格式的可移植性,最好写int32_t
,uint32_t
,int64_t
,...,而不是普通的{ {1}}或int
。这是因为long
(和类似名称)在不同的系统上具有不同的字节数。
如果计划使用PC以外的任何其他设备,则还应注意,不同的系统可能具有不同的字节顺序(大字节序或小字节序)。这种顺序上的差异使得long
的序列化甚至无法跨此类系统移植。为了实现可移植性,最好通过位操作将uint32_t
对象分解为字节,然后序列化这些字节。
对于带符号类型,情况甚至更加复杂,因为在某些专用系统上,最小的uint32_t
值可能会有所不同。幸运的是,这些不是很常见。