С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 09.11.2018
Сообщений: 2

Проблемы с чтением из файла

09.11.2018, 22:24. Показов 1056. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте все! У меня сразу два вопроса. Начну с того, который попроще. Я осваиваю библиотеку fstream, решил написать небольшой кусочек кода с записью-чтением объекта класса. Сам код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
 
#define DB_PATH "members.dat"
#define MSG_PATH "messages.log"
 
class Person {
    string firstName, lastName;
    int age;            
public:
    void input_data () {
        cout << "Enter first name: ";
        cin >> this->firstName;
        cout << "Enter last name: ";
        cin >> this->lastName;
        cout << "Enter age: ";
        cin >> this->age;
        cout << endl;
    }
    void introduce () {
        cout << "Hello! I am " << firstName + " " + lastName + "." << endl;
        cout << "I am " << age << " years old." << endl;
    }
    void writeToDB () {
        ofstream data_fs;
        data_fs.open (DB_PATH, fstream::app);
        if (!data_fs.is_open()) {
            cout << "Error reading file!\n";
            return;
        }
        data_fs.write((char*)this, sizeof(Person));
        data_fs.close();
    }
    void readFromDB () {
        ifstream data_fs;
        data_fs.open (DB_PATH);
        if (!data_fs.is_open()) {
            cout << "Error reading file!\n";
            return;
        }
        data_fs.read((char*)this, sizeof(Person));
        data_fs.close();
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Person foo;
    //При первом запуске на двух нижних строках комментарии убираются
    //А при повторном; при попытке чтения возникает ошибка
    //foo.input_data();
    //foo.writeToDB();
    foo.readFromDB();
    foo.introduce();
    system("pause");
    return 0;
}
Как видите, юзеру предлагается ввести данные об объекте, и объект этот заносится в файл. Затем программа должна считать объект из файла и вывести информацию о нем. И выводит. Но проблема в том, что при закрытии выскакивает "срабатывание исключения с нарушением прав доступа".
Это был первый вопрос.

Второй более глобальный. Изначально я хотел написать код по-другому, вот так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
 
#define DB_PATH "members.dat"
#define MSG_PATH "messages.log"
 
class Person {
    string firstName, lastName;
    int age;            
    static fstream data_fs;
public:
    void input_data () {
        cout << "Enter first name: ";
        cin >> this->firstName;
        cout << "Enter last name: ";
        cin >> this->lastName;
        cout << "Enter age: ";
        cin >> this->age;
        cout << endl;
    }
    void introduce () {
        cout << "Hello! I am " << firstName + " " + lastName + "." << endl;
        cout << "I am " << age << " years old." << endl;
    }
    void writeToDB () {
        data_fs.open (DB_PATH, fstream::out, fstream::app);
        if (!data_fs.is_open()) {
            cout << "Error reading file!\n";
            return;
        }
        data_fs.write((char*)this, sizeof(Person));
        data_fs.close();
    }
    void readFromDB () {
        data_fs.open (DB_PATH, fstream::in);
        if (!data_fs.is_open()) {
            cout << "Error reading file!\n";
            return;
        }
        data_fs.read((char*)this, sizeof(Person));
        data_fs.close();
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Person foo;
    //При первом запуске на двух нижних строках комментарии убираются
    //А при повторном; при попытке чтения возникает ошибка
    //foo.input_data();
    //foo.writeToDB();
    foo.readFromDB();
    foo.introduce();
    system("pause");
    return 0;
}
Отличие в том, что я хотел в качестве члена класса создать статический объект класса fstream, чтобы не создавать его каждый раз для нового объекта Person. Выходит непонятная ошибка на этапе компиляции. fstream нельзя использовать в качестве статического члена? Или вообще нельзя использовать как член другого класса?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.11.2018, 22:24
Ответы с готовыми решениями:

Проблемы с чтением файла на c++
Задача: Сформировать массив данных с помощью структуры. Предметная область – данные о студентах имеющих публикации (номер по порядку,...

Проблемы с чтением файла
Доброго вечера, товарищи. Тут такое дело. Есть массив студентов с их данными. Вроде бы все хорошо, и добавить можно, и удалить нужную...

чтением из файла....
у меня есть два класса... один (базовый) читает строку из файла и присваивает её значение переменной этого типа второй (производный)...

6
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
10.11.2018, 00:40
Цитата Сообщение от Stravinsky Посмотреть сообщение
C++
1
data_fs.write((char*)this, sizeof(Person));
Так можно делать только если класс/структура содержит переменные POD-типов. У вас же переменные типа string хранят свои данные, собственно буфер со строкой, далеко за пределами экземпляра класса Person (в 99% случаев). А в пределах экземпляра класса хранятся только адреса этих буферов. Таким образом, вы записываете в файл только адреса строк, но не сами строки. И считываете аналогично только адреса. Позже, при попытке обратиться к строке, происходит обращение по адресу, где никакой строки нет. И вы получаете access violation при попытке чтения чужой памяти.

Надо примерно так:
C++
1
2
3
4
5
6
7
8
9
    void writeToDB () {
        ofstream data_fs.open (DB_PATH, fstream::out, fstream::app);
        if (!data_fs.is_open()) {
            cout << "Error reading file!\n";
            return;
        }
        data_fs << firstName << ' ' << lastName << ' ' << age << endl;
        data_fs.close();
    }
Это был первый вопрос.

Второй, более глобальный вопрос. Вам же линкер пишет, что не может разрешить один внешний символ. Это как раз ваш статический член класса. Его надо инициализировать отдельно:

C++
1
2
3
4
5
6
7
8
9
class Person {
    string firstName, lastName;
    int age;            
    static fstream data_fs;
public:
    // ...
};
 
fstream Person::data_fs;
Не надо без крайней необходимости использовать статические переменные. Ни в классах, ни в функциях. Исключение - константные переменные, которые по каким-то причинам не должны быть видны извне. Это чревато трудно обнаруживаемыми ошибками. Особенно при многопоточном исполнении.
1
0 / 0 / 0
Регистрация: 09.11.2018
Сообщений: 2
10.11.2018, 10:45  [ТС]
Спасибо за ответ!
То есть, получается, в данном случае следует записывать в файл не сам объект, а последовательно все данные из него?
А как быть, если там будет слишком много полей, чтобы записывать их таким образом?

Не надо без крайней необходимости использовать статические переменные
Значит, в этом случае использование статического члена не оправдано? Я рассуждал так: при первом варианте кода каждый раз будет создаваться новый объект класса fstream, и везде он играет одну и ту же роль, значит (как думал я), имеет смысл сделать его статическим. Может, я не совсем правильно понял, как работает этот класс, но на первый взгляд, везде он делает одно и то же.

Добавлено через 8 минут
И как записывать в файл объект, если среди его членов есть объекты другого класса? Ну, например, у того же класса "человек" будет поле, описывающее его машину (или дом, или еще что-то), а у того объекта, в свою очередь есть куча своих полей.
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.11.2018, 11:12
Цитата Сообщение от Stravinsky Посмотреть сообщение
А как быть, если там будет слишком много полей, чтобы записывать их таким образом?
Какая разница, сколько их? Сделай функцию для записи string и просто вызывай её для каждого string-поля.
Цитата Сообщение от Stravinsky Посмотреть сообщение
И как записывать в файл объект, если среди его членов есть объекты другого класса?
Сделай там функцию записи и вызывай.
0
 Аватар для IP_TCP
7 / 6 / 2
Регистрация: 19.08.2018
Сообщений: 108
10.11.2018, 16:23
Так же разбираю запись/чтение в файл. И тоже решил использовать библиотеку fstream методом класса. Как бы всё работает, но хочется понимания: правильно/неправильно использовать методом. Лучше: в main(е), в функции или же отдельным классом??? Как профи оформляют запись/чтение в файл?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//запись в файл
void Book::RecToFile(std::string &fileName)
{
    std::fstream fs;
    fs.open(fileName, fstream::out | fstream::app);
    if (!fs.is_open())
    {
        cout << "Error" << endl;
    }
    else
    {
        cout << "Open" << endl;
        fs << *this << endl;
    }
    fs.close(); //закрыли файл
 
//чтение из файла
void Book::ReadingIsFile(std::string &fileName)
{
    std::fstream fs;
    fs.open(fileName, fstream::in);
    if (!fs.is_open())
    {
        cout << "Error" << endl;
    }
    else
    {
        cout << "Open for reading" << endl;
        fs.seekg(0);
        while (!fs.eof())
        {
            std::string tempstr;
            getline(fs, tempstr);
            cout << tempstr << endl;
        }
    }
    fs.close();
}
int main()
{
    setlocale(LC_ALL, "Russian");
 
    Book b2("War and Peace", "Tolstoy", 149.50);
    Book b3("Hound of the Baskervilles", "Sir Arthur Conan Doyle", 250.49);
 
    string fileName = "Book.txt";
 
    b2.RecToFile(fileName);
    b3.RecToFile(fileName);
 
    Book ReadIsFile;
    ReadIsFile.ReadingIsFile(fileName);
    
    system("pause");
    return 0;
}
0
7804 / 6568 / 2988
Регистрация: 14.04.2014
Сообщений: 28,705
10.11.2018, 17:56
"Профи" такой ерундой не занимаются.
29-я не нужна, 30-я не верна. А сама функция не связана с классом.
0
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
10.11.2018, 19:41
Цитата Сообщение от Stravinsky Посмотреть сообщение
следует записывать в файл не сам объект, а последовательно все данные из него?
К этому вопросу надо относится творчески. Следует записывать необходимые данные. (Если мы рассматриваем случай, когда мы записываем данные объекта в файл для того, что бы потом создать новый объект того же класса и с тем же наполнением.) Например, если у вас есть бинарное дерево, в котором каждый узел содержит некую информацию и два указателя на поддеревья, то не имеет смысла в файл записывать значения этих указателей, поскольку при восстановлении дерева из файла узлы получат совершенно другие адреса; следовательно, писать в файл надо только целевую информацию из узла.

А так, в принципе, да: писать в файл последовательно все необходимые данные. Даже если их много.

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

Из этого плавно вытекает, что методы класса, предназначенные для ввода/вывода не должны открывать/закрывать файлы, а должны пользоваться потоковыми (файловыми) переменными, передаваемыми им в качестве параметра. Причём потоковая (файловая, в *nix "всё есть файл") переменная может быть связана совсем не с файлом на диске: это может быть, например, консоль или буфер в памяти (см. класс stringstream).

При написании методов для ввода/вывода нужно помнить о симметричности процесса. Т.е. надо писать в файл так, что бы потом было удобно читать. И это не всегда тривиальная задача. Иногда в файл приходится записывать специальные маркеры для обозначения начала и/или конца блока данных, относящихся к одному объекту, а также, возможно, дополнительную информацию, с помощью которой можно отследить целостность данных (например, контрольная сумма).

Часто для классов перегружают операторы >> и << для ввода и вывода данных класса в текстовом формате. Для этого в классе эти функции определяются как дружественные (friend). По правилам, принятым в iostream, "шаблоны" для этих функций следующие:
C++
1
2
3
4
5
6
7
8
9
istream & operator >> (istream & is, CLASS_NAME & data) {
    is >> member1 >> member2 ...
    return is;
}
 
ostream & operator << (ostream & os, const CLASS_NAME & data) {
    os << member1 << member2 ...
    return os;
}
Обратите внимание, что для потоков используются классы без "f" (file). Они являются базовыми классами и для классов файловых потоков.

Для работы с двоичными (нетекстовыми) файлами для методов обычно используют названия read_что_то() и write_что_то(). Опять-таки передавая в качестве аргумента потоковую переменную.

Переходя к от теории к практике: вы, Stravinsky, и вы, IP_TCP, сделали в своём коде почти одинаковые ошибки. Думаю, что вы уже сами поправите свой код после прочтения этой моей писанины.

А вообще ввод/вывод - это достаточно муторная область. По хорошему, перед каждой операцией ввода или вывода нужно проверять состояние потока - не находится ли он в состоянии ошибки. А если находится, то как с этим жить дальше. Считанные данные могут оказаться некорректными... И ещё куча разных ошибок, на которые надо каким-то адекватным способом отреагировать.
Цитата Сообщение от nmcf Посмотреть сообщение
"Профи" такой ерундой не занимаются.
Вы правильно взяли слово "профи" в кавычки.
А для действительных профи "ерунды" в работе не бывает. И это касается любого рода занятий. Извините за банальность.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.11.2018, 19:41
Помогаю со студенческими работами здесь

Ошибка с чтением файла
Добрый вечер, ниже реализована программа по обработке файла данных &quot; Репертуар кинотеатров&quot; в котором указаны название кинотеатра и...

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

Ошибка с чтением файла
Привет, у меня тут проблема. Я сделал программу, которая открывает файл и выводит содержимое на экран, но если я вывожу содержимое второй...

Чтением файла с сервера
Всем привет, столкнулся с ошибкой, но сам не знаю где... Суть программы такова: При запуске программы должен отправляться запрос на...

Проблема с чтением файла
При открытии файла функцией fopen и выводе на консоль отображается только первая строчка. Я так понял что надо открыть файл как бинарный....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru