1

Тема: Зчитування масиву структур з файлу

Маю функцію запису у файл:

void newFile(string file_name, const Worker record[], int number_records)
{
    ofstream f_out(file_name, ios_base :: binary);
    f_out.write((char *) record, sizeof(Worker) * number_records);
    f_out.close();
}


Функція, ніби працює - файл створюється і заповнюється "кракозябрами", при цьому кількість "кракозябр" пропорційно зміється при зміні кількості записів.
І маю функцію зчитування з файлу:

void readFromFile(string file_name, Worker *&records, int &number_records )
{
    ifstream f_in(file_name, ios_base::binary);
    f_in.seekg(0, ios_base :: end);
    cout << f_in.tellg() << "\n";
    number_records = f_in.tellg() / sizeof(Worker);
    records = new Worker [number_records];
    f_in.seekg(0);
    f_in.read((char *)records, sizeof(Worker) * number_records);
    f_in.close();
}

Кількість записів (number_records) рахує правильно, курсор переводиться на початок, здавалось би все добре. Але нічого не зчитує, принаймні оцей масив records має такий вигляд (внизу, на скріншоті, показано, що він заповнений нулевими (порожніми) значеннями):

Прихований текст

http://i.imgur.com/jCt3byB.png

В чому ж проблема?

2 Востаннє редагувалося Itari (18.11.2015 06:50:39)

Re: Зчитування масиву структур з файлу

А як описан Worker? Що це за структура?

Доречі, можливо треба явно визначити відлік позиції від початку.

f_in.seekg(0,f_in.beg);

Хоча варіант з одним параметром повинен робити по абсолюту.

Подякували: koala1

3

Re: Зчитування масиву структур з файлу

Я нічого не зрозумів.

4

Re: Зчитування масиву структур з файлу

Стурктура Worker має ось такий вигляд:

struct PersonalInfo
{
    string surname;
    string name;
    string birthday;
    struct Adress
    {
        string city;
        string street;
        int house_number;
        int flat_number;
    } adress;
    string phone_number;
    string education;                             
};

struct Worker
{
    string ID;
    PersonalInfo personal;
    string department_name;
    string position;
    double salary;
    int experience;
    string work_status;
};
Itari написав:

Доречі, можливо треба явно визначити відлік позиції від початку.

    f_in.seekg(0,f_in.beg);

Хоча варіант з одним параметром повинен робити по абсолюту.

Він працює - це я перевіряла шляхом виведення позиції

5 Востаннє редагувалося koala (18.11.2015 10:19:28)

Re: Зчитування масиву структур з файлу

std::string - це не набір символів рядка, а структура, що містить вказівник на реальний рядок. Його не можна записувати в файл простим write. Або робіть char [] з вказуванням розміру для кожного елементу Worker-а, або перевизначайте ostream& operator<<(Worker) і записуйте стандартними потоками. Ну, або пишіть власну функцію читання/запису для Worker-а.
А ще ви при читанні не видаляєте старий масив.

Подякували: pika19891

6

Re: Зчитування масиву структур з файлу

Стурктура Worker має ось такий вигляд:

У-у-у... Таке дійсно лише серіалізувати доведеться...
Мабудь щодо твого варіанта зі string я тобі пораджу викорістовувати чибто прості текстові файлі, чи XML або INI файли, якщо потрібно структурувати дані. Тоді й читати буде простіше.

7

Re: Зчитування масиву структур з файлу

Зчитування з файлу я робила спираючись на приклад викладача:

Прихований текст
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

struct Person
{    
    string name;
    int age;
};


void Show(const Person &p); 
void SaveToFile(string filename, const Person p[], int size);
void  LoadFromFile(string filename,  Person *&p, int & size);

int  main()
{

    Person persons[]  = { "Ann", 19, "Ivan", 18 , "Oleg", 24, "Lora", 22};
    int numPersons = sizeof(persons) / sizeof(Person );

    SaveToFile("Persons.dat", persons, numPersons); //пишемо у файл масив персон

    Person * base;
    int numInBase = 0;
    LoadFromFile("Persons.dat", base, numInBase); //читаємо з файлу дані у масив персон

    for(int i = 0; i < numInBase; ++i) 
        Show(base[i]);

}
void Show(const Person &p) 
{
    cout << "Person " << p.name << ' ' << p.age <<endl;
}

void SaveToFile(string filename, const Person p[], int size)
{
    ofstream file(filename, ios_base::binary); // відкрили бінарний файловий потік для запису 

    file.write((char * )p, sizeof(Person) * size); //пишемо всі екземпляри масиву персон у файл

    cout << "We are writing(into file) " << size  << "persons\n";
    file.close();
}
void  LoadFromFile(string filename,  Person *&p, int & size)
{
    ifstream file(filename,  ios_base::binary); // відкрили бінарний файловий потік для читання
    file.seekg(0, ios_base::end); //перемістили файловий курсор у кінець файлу
    size = file.tellg() / sizeof(Person); //обчислили кількість екземплярів Person, що записана у файлі

    p = new Person [size]; // створили дин масив, куди будемо читати дані про персон

    file.seekg(0);// перейшли на початок файлу
    file.read((char * )p, sizeof(Person) * size); // читаємо з файл все( у масив р)
    cout << "\nWe are loading data(from  file) int array of Persons\n\n";
    file.close();

}

І тут все працює, думала і у мене все буде працювати :(

8 Востаннє редагувалося Itari (18.11.2015 11:08:10)

Re: Зчитування масиву структур з файлу

І тут все працює

Щось мені в це туго віриться...
Ти впевнена, що у файл заносяться саме ті дані, які були введені?

P.S. Здається я здогадавсь чому приклад викладача працює... Якщо я прав, то такому викладачу треба попиці піццею надавати. А потім до швецької стінки прибити Nine Inch Nails-ами за такі приклади.

Подякували: koala1

9 Востаннє редагувалося koala (18.11.2015 11:07:22)

Re: Зчитування масиву структур з файлу

Я б такого викладача...   *WALL*  *FACEPALM*  *FACEPALM*  *FACEPALM*   :|
Тут працює, бо адреси з string-ів записуються в файл, після чого одразу читаються. А от якщо в проміжку закрити програму, то нічого не вийде.

10

Re: Зчитування масиву структур з файлу

Я програму викладача переробила ось так:

Прихований текст
#include <iostream>
#include <string>
#include <fstream>
#include <conio.h>
using namespace std;

struct Person
{
    string name;
    int age;
    string gender;
};


void Show(const Person &p);
void SaveToFile(string filename, const Person p[], int size);
void  LoadFromFile(string filename, Person *&p, int & size);

int  main()
{

    //Person persons[] = { "Ann", 19, "Ivan", 18, "Oleg", 24, "Lora", 22 };
    
    const int NUMBER_PERSONS = 5;
    Person persons[NUMBER_PERSONS];
    int numPersons = sizeof(persons) / sizeof(Person);
    Person * base;
    int numInBase = 0;

    int choice;
    bool exit = false;
    do{
        system("cls");
        cout << "1 - Save to file\n";
        cout << "2 - Load from file\n";
        cout << "0 - exit\n";
        cout << "Choice: ";
        cin >> choice;
        switch (choice)
        {
        case 1:
            system("cls");
            for (int i = 0; i < NUMBER_PERSONS; ++i)
            {
                cout << "Enter name: ";
                cin >> persons[i].name;
                cout << "Enter age: ";
                cin >> persons[i].age;
                cout << "Enter gender: ";
                cin >> persons[i].gender;
            }
            SaveToFile("Persons.dat", persons, numPersons); //пишемо у файл масив персон
            break;
        case 2:
            system("cls");
            LoadFromFile("Persons.dat", base, numInBase); //читаємо з файлу дані у масив персон

            for (int i = 0; i < numInBase; ++i)
                Show(base[i]);
            break;
        case 0:
            exit = true;
            break;
        }
        _getch();
    } while (!exit);
}
void Show(const Person &p)
{
    cout << "Person " << p.name << ' ' << p.age << " " << p.gender << endl;
}

void SaveToFile(string filename, const Person p[], int size)
{
    ofstream file(filename, ios_base::binary); // відкрили бінарний файловий потік для запису 

    file.write((char *)p, sizeof(Person) * size); //пишемо всі екземпляри масиву персон у файл

    cout << "We are writing(into file) " << size << "persons\n";
    file.close();
}
void  LoadFromFile(string filename, Person *&p, int & size)
{
    ifstream file(filename, ios_base::binary); // відкрили бінарний файловий потік для читання
    file.seekg(0, ios_base::end); //перемістили файловий курсор у кінець файлу
    size = file.tellg() / sizeof(Person); //обчислили кількість екземплярів Person, що записана у файлі

    p = new Person[size]; // створили дин масив, куди будемо читати дані про персон

    file.seekg(0);// перейшли на початок файлу
    file.read((char *)p, sizeof(Person) * size); // читаємо з файл все( у масив р)
    cout << "\nWe are loading data(from  file) int array of Persons\n\n";
    file.close();

}

І вона знову ж таки працює... Може я чогось не розумію...

11 Востаннє редагувалося Itari (18.11.2015 12:35:38)

Re: Зчитування масиву структур з файлу

І вона знову ж таки працює...

Запусти програму. Створи та наповни файл. Закрий программу, заново запусти. Считай з файла одразу після запуску й подивись буде вона працювати чи зчитае якусь "лабудусь".

Подякували: pika19891

12

Re: Зчитування масиву структур з файлу

Детальніше. Програма робить так:
1. виділяє пам'ять для string-а;
2. записує цю адресу (не рядок, а тільки адресу!) в файл;
3. читає адресу;
4. використовує рядок.
Якщо між пунктами 2 і 3 програму закрити, то в новій програмі вже не буде тих даних за тою адресою, і програма буде звертатися бозна-куди. Якщо ж не закривати, то програма працює, але робить дуже дивні речі.

Подякували: pika19891

13

Re: Зчитування масиву структур з файлу

Itari написав:

І вона знову ж таки працює...

Запусти програму. Створи та наповни файл. Закрий программу, заново запусти. Считай з файла одразу після запуску й подивись буде вона працювати чи зчитае якусь "лабудусь".

Саме так і перевіряла - працює

14 Востаннє редагувалося Itari (18.11.2015 14:11:25)

Re: Зчитування масиву структур з файлу

Саме так і перевіряла - працює

Я не раджу тобі так робити ні в якому разі. Це лише самісіньке везіння.
краще опиши серіалізацію щось таке:

void SaveToFile(string filename, const Person p[], int size)
{
    ofstream file(filename, ios_base::binary); // відкрили бінарний файловий потік для запису 
    file.write((char*)&size,sizeof(size));
    for(int i=0;i<size;i++){
        int v=p[i].age; file.write((char*)&v,sizeof(int));
        v=p[i].gender.length(); file.write((char*)&v,4);
          file.write(p[i].gender.c_str(),p[i].gender.length());
        v=p[i].name.length(); file.write((char*)&v,4);
          file.write(p[i].name.c_str(),p[i].name.length());
    }
    cout << "We are writing(into file) " << size << "persons\n";
    file.close();
}

І зчитування:

void  LoadFromFile(string filename, Person *&p, int & size)
{
    ifstream file(filename, ios_base::binary); // відкрили бінарний файловий потік для читання

    file.read((char *)&size, sizeof(size));
    p = new Person[size]; // створили дин масив, куди будемо читати дані про персон
    int v;
    char *s;
    for(int i=0;i<size;i++){
         file.read((char*)&v,sizeof(int));
         p[i].age=v;

         file.read((char*)&v,sizeof(int));
         s=new char[v+1]; memset(s,0,v+1);
         file.read(s,v);
         p[i].gender.assign(s);

         file.read((char*)&v,sizeof(int));
         s=new char[v+1];memset(s,0,v+1);
         file.read(s,v);
         p[i].name.assign(s);
    } 
    cout << "\nWe are loading data(from  file) int array of Persons\n\n";
    file.close();
 
}

Це надійніше, ніж те, що тобі кволі преподи дали.
Хоча треба визнати, що оформлено не дюже добре, але прінципи серіалізации демонструє.

Подякували: pika19891

15 Востаннє редагувалося pika1989 (18.11.2015 15:21:41)

Re: Зчитування масиву структур з файлу

Я Вам дякую, буду розбиратись...
Але є одне питання: якщо брати мою стурктуру Worker, то мені для кожного поля таким чинном прописувати?

16

Re: Зчитування масиву структур з файлу

мені для кожного поля таким чинном прописувати?

Найгарніше буде, якщо ти так й зробиш. Саме під такі завдання й роблять класи, у яких монтуються спеціальні методи накштал тих, що я показав. Тоді кожен екземпляр об'єкту сам себе зчитуе та записує.
Почитай про серіалізацію, як вона робиться та навіщо. Якщо ти вчишся на ІТ то тобі буде це в користь.

Подякували: pika19891

17

Re: Зчитування масиву структур з файлу

Itari, може Ви порадите, де можна більш детально почитати про серіалізацію, буду дуже вдячна

18 Востаннє редагувалося pika1989 (18.11.2015 15:50:17)

Re: Зчитування масиву структур з файлу

Саме під такі завдання й роблять класи, у яких монтуються спеціальні методи

На жаль, ми їх ще не вивчали, але іноді руки так і "чешуться" зробити шось по-іншому))

19

Re: Зчитування масиву структур з файлу

pika1989 написав:

Itari, може Ви порадите, де можна більш детально почитати про серіалізацію, буду дуже вдячна

Да в гуглі. Деж ще? На вікіпедіі здається було щось...

ми їх ще не вивчали

Ну з такими преподоносорами ви взагалі нічого цінного не вивчите. Лише самі баготворення.