尝试将记录中的数据读取到程序中时难以捉摸的错误(C ++)

时间:2019-03-10 04:24:36

标签: c++ c++14

我正在尝试制作一个程序,该程序可以将数据读写到数据文件中。由于某种原因,我无法弄清楚,它无法仅从名称和数字名称中读取文件中的字符。我需要字符,以便显示项目列表。

文件中的数据是记录,结构是这个,尝试获取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的无效转换”。

1 个答案:

答案 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_tuint32_tint64_t,...,而不是普通的{ {1}}或int。这是因为long(和类似名称)在不同的系统上具有不同的字节数。

如果计划使用PC以外的任何其他设备,则还应注意,不同的系统可能具有不同的字节顺序(大字节序或小字节序)。这种顺序上的差异使得long的序列化甚至无法跨此类系统移植。为了实现可移植性,最好通过位操作将uint32_t对象分解为字节,然后序列化这些字节。

对于带符号类型,情况甚至更加复杂,因为在某些专用系统上,最小的uint32_t值可能会有所不同。幸运的是,这些不是很常见。