Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.05.2010, 13:36   #1
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию Чтение/запись объектов классов из/в бинарные файлы

Доброго времени суток!
Так уж получилось, что до недавнего времени работать с бинарными файлами мне не доводилось, и вот теперь я решил исправить этот недостаток.
Для начала я решил записать/считать объект класса, гордо поименованного Базой Данных, содержащего очень простые поля - строку, массив целых чисел, а также длины строки и массива. Оба массива динамические.
Я попробовал реализовать функции-члены чтения/записи всех данных класса, начав с функции записи.
Получилось примерно вот что:
Код:
class DB
   {
   public:
   DB(int len, char* name, int size, int* arr);
   void Print() const;
   void SaveToFile(const char* FileName) const;
   void LoadFromFile(const char* FileName) const;
   private:
   int NameLen;
   char* Name;
   int ArrSize;
   int* Array;
   };
DB::DB(int len, char* name, int size, int* arr):
   NameLen(len), ArrSize(size)
   {
   Name = new char[NameLen];
   for (int i = 0; i < NameLen; i++)
      Name[i] = name[i];
   Array = new int[ArrSize];
   for (int i = 0; i < ArrSize; i++)
      Array[i] = arr[i];
   }
void DB::Print() const
   {
   std::cout << "Name: " << Name << std::endl;
   std::cout << "Array: ";
   for (int i = 0; i < ArrSize; i++)
      std::cout << Array[i] << " ";
   std::cout << std::endl;
   }
void DB::SaveToFile(const char* FileName) const
   {
   std::ofstream file(FileName, std::ios::binary);
   file.write(reinterpret_cast<char*>(&NameLen), sizeof(int));
   file.write(Name, sizeof(Name));
   file.write(reinterpret_cast<char*>(&ArrSize), sizeof(int));
   for (int i = 0; i < ArrSize; i++)
      file.write(reinterpret_cast<char*>(&Array[i]), sizeof(int));
   file.close();
   }
Компилятор (Билдер 6.0) заругался на следующие две строчки:
Код:
   file.write(reinterpret_cast<char*>(&NameLen), sizeof(int));
//...
   file.write(reinterpret_cast<char*>(&ArrSize), sizeof(int));
Цитата:
[C++ Error] main.cpp(39): E2031 Cannot cast from 'const int *' to 'char *'
[C++ Error] main.cpp(41): E2031 Cannot cast from 'const int *' to 'char *'
Причем в функции main строчка вроде
Код:
int size;
char* c = reinterpret_cast<char*>(&size);
нареканий не вызывала.
Почесав немного репу сменил параметр с char* на const char*. Вроде бы и впрямь удалось что-то записать в файл. Правда, по-моему, записал только кусок строки. (заменил sizeof(Name) на NameLen - пишет вроде нормально, главная проблема все равно не решилась).
Ладно, решил по образу и подобию слепить функцию загрузки из файла:
Код:
void DB::LoadFromFile(const char* FileName) const
   {
   std::ifstream file(FileName, std::ios::binary);
   file.read(reinterpret_cast<const char*>(&NameLen), sizeof(int));
   file.read(Name, NameLen);
   file.read(reinterpret_cast<const char*>(&ArrSize), sizeof(int));
   for (int i = 0; i < ArrSize; i++)
      file.read(reinterpret_cast<char*>(&Array[i]), sizeof(int));
   file.close();
   }
Получаю ошибки:
Цитата:
[C++ Error] main.cpp(49): E2034 Cannot convert 'const char *' to 'char *'
[C++ Error] main.cpp(49): E2342 Type mismatch in parameter '__s' (wanted 'char *', got 'const char *')
[C++ Error] main.cpp(51): E2034 Cannot convert 'const char *' to 'char *'
[C++ Error] main.cpp(51): E2342 Type mismatch in parameter '__s' (wanted 'char *', got 'const char *')
Пытаюсь решить при помощи грубой силы:
Код:
void DB::LoadFromFile(const char* FileName) const
   {
   std::ifstream file(FileName, std::ios::binary);
   file.read(const_cast<char*>(reinterpret_cast<const char*>(&NameLen)), sizeof(int));
   file.read(Name, NameLen);
   file.read(const_cast<char*>(reinterpret_cast<const char*>(&ArrSize)), sizeof(int));
   for (int i = 0; i < ArrSize; i++)
      file.read(reinterpret_cast<char*>(&Array[i]), sizeof(int));
   file.close();
   }
Компилируется, пытаюсь считать базу из файла:
Код:
DB* FileDB;
FileDB -> LoadFromFile("DataBase.db");
FileDB -> Print();
Результат - предсказуемый. Access violation.

Таким образом прошу подсказать мне - почему же члены класса имеют тип данных const, а также в чем я наошибался и как надо делать правильно?
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 18.05.2010, 14:11   #2
mrChester
Я
Форумчанин
 
Аватар для mrChester
 
Регистрация: 24.04.2010
Сообщений: 693
По умолчанию

Использовать reinterpret_cast это уже не лучший выход, да еще и в сочетании с const_cast, отсюда и потеря данных
Все персонажи вымышлены, все совпадения случайны.
Если жизнь игра, тогда я её разработчик ©.
mrChester вне форума Ответить с цитированием
Старый 18.05.2010, 14:22   #3
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Цитата:
в сочетании с const_cast
Безусловно! Это я пытался вообще пальцем в небо тыкнуть. Что логично, не попал. Но что тогда конкретно надо делать??
И как еще писать данные в бинарные файлы без явного (или - упаси бог! - неявного) преобразования? write и read без этого не работают, а других способов работы с бинарными файлами я не знаю. (про сишные функции не говорю - я хотел бы работать со средствами C++, в данном случае - с потоками)
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 18.05.2010, 14:24   #4
mrChester
Я
Форумчанин
 
Аватар для mrChester
 
Регистрация: 24.04.2010
Сообщений: 693
По умолчанию

В общем в этих строчках нужно просто преобразовать значения в строковую переменную
Код:
 
file.write(itoa(NameLen,&str,10), sizeof(str));
Что-то вроде этого должно быть, я опять таки не могу проверить
Все персонажи вымышлены, все совпадения случайны.
Если жизнь игра, тогда я её разработчик ©.
mrChester вне форума Ответить с цитированием
Старый 18.05.2010, 14:36   #5
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Ну это уже костыли. Как-никак я хочу писать в бинарный файл и использовать его преимущества, в том числе и компактность представления численных данных по сравнению с текстовым представлением. Гораздо лучше записать (2^32-1) как целое в четыре байта, чем как строку в 10 байт. А уж как записывать массив целых? Либо на текст каждого числа те самые 10 байт отводить, либо... Ну да, либо указывать длину строкового представления каждого числа и тоже его записывать. В общем, потери в 2,5 раза.
Да и какой он после этого бинарный файл?
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 18.05.2010, 15:19   #6
mrChester
Я
Форумчанин
 
Аватар для mrChester
 
Регистрация: 24.04.2010
Сообщений: 693
По умолчанию

Так будет правильнее:
Код:
               file.write(static_cast<char const*>(static_cast<void const*>(&NameLen)), sizeof(int));
	file.write(Name, sizeof(Name));
	file.write(static_cast<char const*>(static_cast<void const*>(&ArrSize)), sizeof(int));
Все персонажи вымышлены, все совпадения случайны.
Если жизнь игра, тогда я её разработчик ©.
mrChester вне форума Ответить с цитированием
Старый 18.05.2010, 15:57   #7
mrChester
Я
Форумчанин
 
Аватар для mrChester
 
Регистрация: 24.04.2010
Сообщений: 693
По умолчанию

Вот еще откопал примеры чтения и записи:
Код:
#include <fstream.h>

struct mystruct {
   long   i;
   char   buf[5];
   double d;
};

int main()
{
   fstream f("file.dat",ios::binary|ios::in|ios::out);
   mystruct ms;
   //добавляем новую структуру в бинарник
   f.write((unsigned char*)&ms, sizeof(ms));
   //...
   mystruct m;
   //читаем первую записанную структуру 
   f.read((unsigned char*)&ms,sizeof (ms));
   return 0;
}
Все персонажи вымышлены, все совпадения случайны.
Если жизнь игра, тогда я её разработчик ©.
mrChester вне форума Ответить с цитированием
Старый 18.05.2010, 16:39   #8
oleg kutkov
Unix C++ developer
Форумчанин
 
Аватар для oleg kutkov
 
Регистрация: 16.04.2007
Сообщений: 651
По умолчанию

Почитайте про сериализацию/десериализацию данных.
oleg kutkov вне форума Ответить с цитированием
Старый 18.05.2010, 20:28   #9
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

mrChester, знаю про этот вариант. Не подходит, т.к. массивы динамические, а делать статическими - не вариант.
oleg kutkov, хорошо, посмотрю что пишут.

Если имеется еще какая-то информация по теме - буду рад узнать!
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 18.05.2010, 22:20   #10
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Балда я необразованная! Константные-то члены потому, что я функции объявил как const (особенно мудро это с LoadFromFile!!)! Нет во мне еще тонкого чувства констант...
Впрочем, проблема с Access violation пока остается.

UPD. За-ме-ча-тель-но! Кто будет выделять память под массивы, в которые все это счастье будет считываться - после 1837 года стало непонятно...
В общем, ошибки, как всегда, идиотские - зато название темы звучит гордо!
Остались, правда, еще небольшие косяки, ну да с ними, думаю, разберусь.

UPD2. С проблемой разобрался окончательно, тему можно закрывать!
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же

Последний раз редактировалось Гром; 18.05.2010 в 22:34.
Гром вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Файлы: запись/чтение Proger_1 БД в Delphi 0 30.04.2010 00:36
Структуры,запись в бинарные файлы,массивы(С++) TOSHH Общие вопросы C/C++ 1 10.10.2009 02:01
VC++ файлы(чтение\запись) ("")(Э_Є)("") Общие вопросы C/C++ 3 16.06.2009 14:05
Создание классов и использование объектов классов при написании программ в среде C++. Frozen inside Помощь студентам 0 16.04.2009 23:18
Проекция файла и запись/чтение объектов класса в C++ sd13 Помощь студентам 26 25.05.2008 12:05