Страницы

Поиск по вопросам

вторник, 30 апреля 2019 г.

Как корректно записать/считать в/из файла структуру с полями типа string?

Имеется структура
struct User { string login; string password; };
Стоит задача сделать примитивную авторизация пользователя. Т.е. создается файлик, в него записывается заполненный объект вышеуказанной структуры, а при последующих запусках производится запрос логина+пароля, считываются данные из файлика и сравниваются. Код:
#include #include #include #include #include
using namespace std;
struct User { string login; string password; };
void main () { SetConsoleCP (1251); // установка универсальной кодировки SetConsoleOutputCP (1251);
string path; int realsize=0; User u; vector U; bool exit = false;
do { system("cls"); cout<<"Укажите, на каком диске находится файл с регистрационными данными:
"; getline(cin, path); path += ":\\users.txt"; ifstream fin(path, ios_base::binary | ios_base::in);
if (fin.is_open()) { cout<<"Отлично, ваш файл найден!
"; fin.read((char*)&u, sizeof(User)); U.push_back(u); fin.close(); cout << "Введите логин:
"; getline(cin, u.login); cout << "Введите пароль:
"; getline(cin, u.password); if (!U.at(0).login.compare(u.login) && !U.at(0).password.compare(u.password)) { cout << "Вы авторизованы!
"; } else { cout << "Вы не авторизованы!
"; } exit = true; } else { cout << "Файл не найден и будет создан"; ofstream fout (path, ios_base::binary | ios_base::out); if (fout.is_open()) { cout << "Введите логин:
"; getline(cin, u.login); cout << "Введите пароль:
"; getline(cin, u.password); fout.write((char*)&u, sizeof(User)); fout.close(); cout << "Файл создан и данные внесены!
"; } else { cout << "Ошибка при создании файла! Работа приложения будет завершена.
"; exit = true; } } } while(!exit);
system("pause");
}
Вся беда в том, что при выполнении данного кода появляется ошибка:
Необработанное исключение по адресу 0x0FDECCC8 (msvcp110.dll) в test.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x0067ADE4.
Кадры стека вызовов:

Путем экспериментов установлено, что замена использования вектора на простой динамический массив никак не влияет на ошибку (т.е. она по-прежнему появляется), а вот замена использования string на char * приводит к устранению проявления данной ошибки. Погуглив, я пришел в выводу, что возникает какая-то ошибка в деструкторе string (могу ошибаться). Может кто-нибудь прояснить ситуацию и дать рекомендации по корректному использованию типа string в данного рода задачах?


Ответ

Самый простой способ (как уже упомянул в комментарии @pavel) - использовать текстовый режим работы с файлом и операторы форматированного ввода/вывода (operator<<, operator>>) для чтения/записи std::string из/в потока.
Чтение:
ifstream fin(path); if (fin) { fin >> u.login >> u.password; }
Запись:
ofstream fout(path); if (fout) { // Разделители нужны для последующего считывания fout << u.login << " " << u.password << "
"; }
При этом данный подход накладывает некоторые ограничения на строки: как минимум они не должны содержать в себе символы пробельной группы, т.к. такой символ будет расценен как разделитель.
Функции istream::read, ostream::write в этом случае не используются вовсе. Причина, по которой они не работают как надо указана в ответе @gbg.

Комментариев нет:

Отправить комментарий