Неуловимая ошибка при попытке прочитать данные из записи в программу (C ++) - PullRequest
0 голосов
/ 10 марта 2019

Я пытаюсь создать программу, которая читает и записывает данные в файл данных.По какой-то причине я не могу понять, он не может прочитать символ из файла только имя и числовое имя.Мне нужен символ, чтобы я мог отобразить список элементов.

Данные в файле - это запись, структура такая, и при попытке получить символ возникает ошибка.

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, которую я назвал input, которая записывает данные в файл.Это для книги, есть три других варианта, поэтому у них есть символ, чтобы определить, к какому жанру относятся данные.

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 похож начто.

Ошибка возникает при попытке прочитать данные из файла (в функции void, которую я назвал Modify), я также попытался просто использовать обычный текстовый файл и все еще столкнулся с той же проблемой.

     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 повторяется только один раз, когда имеется более одной записи.Также change.Genre никогда не имеет фактического значения, поэтому записи не отображаются.Я не могу прочитать имя или данные символа, только двойные / целые числа.Книга 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 Ответ

2 голосов
/ 10 марта 2019

Строка, которая, как и любой объект, который может содержать указатели, не может быть записана с 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

Чтение должно быть сделано таким же образом.

Примечание : процесс записи ичтение объектов в и из файлов обычно называется сериализацией и десериализацией.Например, повысить сериализацию .

Примечание 2: Для переносимости форматов файлов лучше написать int32_t, uint32_t, int64_t,..., а не простой int или long.Это потому, что long (и аналогичные) имеют разное количество байтов в разных системах.

Если вы планируете использовать что-либо, кроме ПК, вам также следует помнить, что разные системы могут иметь разный порядок байтов (с большим или меньшим порядковым номером).Эта разница в заказе делает сериализацию даже uint32_t непереносимой в таких системах.Для переносимости лучше разбить uint32_t объекты на байты с помощью битовой операции и сериализовать эти байты.

Для типов со знаком все еще сложнее, поскольку наименьшее возможное значение int32_t может отличаться в некоторых специализированных системах.К счастью, тезисы не очень распространены.

...