Как записать структуру в файл в си
Перейти к содержимому

Как записать структуру в файл в си

  • автор:

Как записать структуру в файл в си

Есть у меня некая структура (struct).
Требуется создать файл, куда писать данные в виде этих структур. А также читать. А также перемещаться по файлу.
Как это сделать? (Плиз с ма-аленьким примером или в какую сторону копать).
Заранее спасибо.

Запись и чтение структур в/из файл(а)

От: IT linq2db.com
Дата: 11.10.02 04:19
Оценка: 100 (18) +2 -2
#Имя: FAQ.cpp.struct2file

Почему ламерский? Нормальный вопрос, который обычно встречается большинству программеров.

ПА>Есть у меня некая структура (struct).
ПА>Требуется создать файл, куда писать данные в виде этих структур. А также читать. А также перемещаться по файлу.
ПА>Как это сделать? (Плиз с ма-аленьким примером или в какую сторону копать).

Всё зависит от многих вещей, как всегда

Для начала давай объявим твою структуру:

struct mystruct < int i; char buf[20]; double d; >;

Теперь, допусти, нам нужно положить её в файл средствами C/C++.

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

#include #include #include #include #include struct mystruct < int i; char buf[5]; double d; >; int main(int argc, char* argv[]) < // открываем файл int fh = _open("file.dat",_O_RDWR | _O_BINARY); if (fh == -1) < // или при необходимости создаём новый fh = _creat("file.dat",_S_IREAD | _S_IWRITE); if (fh == -1) // не шмагла :xz: return 1; > // готовим структуру для записи mystruct ms; memset(&ms,0,sizeof ms); ms.i = 1; ms.d = 2; // позиционируемся в конец файла _lseek(fh,0,SEEK_END); // добавляем новую структуру _write(fh,&ms,sizeof ms); // позиционируемся в начало _lseek(fh,0,SEEK_END); // читаем первую записанную структуру _read(fh,&ms,sizeof ms); return 0; >

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

Всё казалось бы нормально, но если ты посмотришь размер созддаваемого файла, то он всегда будет кратен 24 байтам (вариант Visual C++), хотя размер структуры равен 4+5+8=17 байт. Это происходит потому, что компиляторы по умолчанию выравнивают размер структур в целях оптимизации. Следовательно, наша первая задача отменить это поведение по умолчанию. Стандартных средств сделать это нет, но как правило компиляторы содержат специальную опцию коммандной строки и/или прагму, позволяющую это делать.

Ещё одной неверной деталью в нашем примере является использование типа переменной int. Для разных версий операционных систем размер инта может быть разным и лучше явно указать размер используемого типа — short или long.

Изменим описание структуры:

#pragma pack(push,1) struct mystruct < long i; char buf[5]; double d; >; #pragma pack(pop)

Теперь запись в файл даст вполне ожидаемый результат.

Здесь можно отметить ещё одну деталь. В качестве строки я использовал массив char[5]. Использование классов типа CString std::string не приведёт ни к чему хорошему. Фактически ты сохранишь не саму строку, а содержимое класса, который её реализует. Допустим, класс CMyString реализован следующим образом:

class CMyString < public: int len; char *str; // . >;

Объявление такой структуры как

struct mystruct < long i; CMyString str; double d; >;

будет фактически соответствовать следующему варианту:

struct mystruct < long i; int str_len; char *str_str; double d; >;

Т.е. в месте, где ты ожидаешь строку будет указатель на буфер в памяти, который (в смысле не буфер, а указатель на него) ты благополучно и сохранишь в файле.

Теперь рассмотрим вариант с потоками. Вообще-то, лучше конечно использовать новую версию , но у меня она до сих не вызывает никакого доверия. По-этому, воспользуемся старым вариантом:

#include #include #pragma pack(push,1) struct mystruct < long i; char buf[5]; double d; >; #pragma pack(pop) int main(int argc, char* argv[]) < // создаём или открываем файл fstream f("file.dat",ios::binary|ios::in|ios::out); // готовим структуру для записи mystruct ms; memset(&ms,0,sizeof ms); ms.i = 1; ms.d = 2; // позиционируемся в конец файла f.seekp(0,ios::end); // добавляем новую структуру f.write((unsigned char*)&ms,sizeof ms); // позиционируемся в начало f.seekp(0,ios::beg); // читаем первую записанную структуру f.read((unsigned char*)&ms,sizeof ms); return 0; >

Ниже вариант использования Windows API вместо фуекций CRTL:

#include #pragma pack(push,1) struct mystruct < long i; char buf[5]; double d; >; #pragma pack(pop) int main(int argc, char* argv[]) < // создаём или открываем файл HANDLE fh = ::CreateFile( TEXT("file.dat"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // готовим структуру для записи mystruct ms; memset(&ms,0,sizeof ms); ms.i = 1; ms.d = 2; // позиционируемся в конец файла ::SetFilePointer(fh,0,0,FILE_END); // добавляем новую структуру DWORD dw=0; ::WriteFile(fh,&ms,sizeof ms,&dw,NULL); // позиционируемся в начало ::SetFilePointer(fh,0,0,FILE_BEGIN); // читаем первую записанную структуру ::ReadFile(fh,&ms,sizeof ms,&dw,NULL); return 0; >

Еще можно привести вариант исользования класса CFile из MFC, но, в принципе, он будет не очень сильно отличаться.

Может я немного увлёкся, но главное чтобы было понятно

ЗЫ. Далше тебя ждут другие вопросы:

  1. Как узнать количество записанных структу в файле?
    Правильный ответ — не вычислять это по размеру файла, а добавить в начало заголовок (специальную структуру), содержащую необходимую служебную информацию: фактический размер файла, версию формата, число записей, смещение к первому блоку и т.п.
  2. Как добавлять записи переменной длины?
    Можно к каждой записи добавить свой заголовок, описывающий её структуру.
  3. Как удалять ненужные записи из файла?
    Можно просто помечать их как удалённые, а в последствии организовать упаковку файла. Можно организовать список удалённых страниц и использовать их в дальнейшем вместо добавления новых в конец.
  4. Как обеспечить совместный доступ к файлу из нескольких программ.
    Блокировки, отдельный сервер доступа и ещё куча всяких вариантов.
  5. Как сделать динамическую структуру записей в файле.
    У-у-у.

Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Про файлы.

От: Панкратов Александр
Дата: 11.10.02 04:43
Оценка:

Огромное спасибо, очень исчерпывающе.
IT>После всего этого возникает вполне законный вопрос — а может лучше сразу взять стандартную базу данных?
IT>Шутю я, шутю.
Если бы речь шла об обычных виндах — я бы так и сделал
Однако все происходит в WinCE. Да еще на обкоцанном варианте Casio. Поэтому с ADOCE возникают некоторые проблемы.

Re[2]: Переносимость short и long ?

От: Vi2 http://www.adem.ru
Дата: 11.10.02 04:52
Оценка:

Здравствуйте IT, Вы писали:

IT>Ещё одной неверной деталью в нашем примере является использование типа переменной int. Для разных версий операционных систем размер инта может быть разным и лучше явно указать размер используемого типа — short или long.

Интересно, неужели для разных версий операционных систем размеры short или long, в отличие от int, одинаковы?
Насколько я помню, есть sizeof(short int)

Так что и использование short или long не даст переносимости.

Vita Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[3]: Про файлы.

От: orangy http://twitter.com/orangy
Дата: 11.10.02 06:19
Оценка: 6 (1)

Здравствуйте Панкратов Александр, Вы писали:

IT>>После всего этого возникает вполне законный вопрос — а может лучше сразу взять стандартную базу данных?
ПА>Однако все происходит в WinCE. Да еще на обкоцанном варианте Casio. Поэтому с ADOCE возникают некоторые проблемы.
Тогда у тебя возникает еще ряд проблем:
— CE система юникодная, осторожнее со строками при записи и чтении
— не помню какой Endian на Casio (это кажется был MIPS), осторожнее с переносом файлов с win32
— нельзя игнорировать alignment, точнее он должен быть на 4 байта. MIPS не позволяет адресовать 32-битное число по невыровненному адресу
это важно, если ты собираешься читать массивами структур

I would recommend using WINAPI CreateFile, ReadFile, . functions тьфу блин, совсем зарапортавался.

Используй WINAPI CreateFile, ReadFile, . — в winCE другого может и не быть, лучше всего завернуть это дело в портабельную оболочку.
Всегда указывай полный путь до файла, в WinCE нет понятия «текущая директория», если нужно — возьми у текущего модуля.
TCHAR buf[_MAX_PATH+30];
GetModuleFileName(hInstance, buf, _MAX_PATH);

Если объёмы данных небольшие — используй XML. Была где-то библиотека портированная для CE, поищи.

Янус 1.0 alpha 10: Orangy
«Develop with pleasure!»
Re[3]: Переносимость short и long ?

От: Павел Кузнецов
Дата: 11.10.02 08:13
Оценка:

Здравствуйте Vi2, Вы писали:

IT>>Ещё одной неверной деталью в нашем примере является использование типа переменной int. Для разных версий операционных систем размер инта может быть разным и лучше явно указать размер используемого типа — short или long.

Здесь IT был не вполне точен.

Vi2>Интересно, неужели для разных версий операционных систем размеры short или long, в отличие от int, одинаковы?

Не только для разных операционных систем, но и для разных компиляторов на одной операционной системе размеры short, long и int могут различаться.

Vi2>Насколько я помню, есть sizeof(short int)

Кроме указанного соотношения есть еще требования к минимальному диапазону представляемых значений:

short -32767 . . . +32767 (минимум 16 бит) int -32767 . . . +32767 (минимум 16 бит) long -2147483647 . . . +2147483647 (минимум 32 бита)

Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Переносимость short и long ?

От: IT linq2db.com
Дата: 11.10.02 11:31
Оценка:

Здравствуйте Vi2, Вы писали:

Vi2>Интересно, неужели для разных версий операционных систем размеры short или long, в отличие от int, одинаковы?

Ну если считать Windows 3.1 и Windows 95 разными версиями то да К тому же MS выпустила там чего-то 64 разрядное кажется, там уже и long поплывёт.

Vi2>Насколько я помню, есть sizeof(short int)
Vi2>Так что и использование short или long не даст переносимости.

Ладно придираться, я только обозначил проблему.

Если нам не помогут, то мы тоже никого не пощадим.
Re: Запись и чтение структур в/из файл(а)

От: AndrewS42
Дата: 06.06.05 06:58
Оценка:

Здравствуйте, IT, Вы писали:

IT>Всё зависит от многих вещей, как всегда

Это точно! Несмотря на то, что топику уже несколько лет, я хотел бы вставить свои 5 копеек в обсуждаемую тему, тем более, что эта тема находится в статьях сайта, а значит не имеет срока давности.
Наиболее правильным и переносимым (но медленным) будет вообще не сохранять в файл структуру целиком. Более того, не желательно даже int записывать в файл напрямую. Одна из причин уже была озвучена в топике: несовпадающие размеры int в разных компиляторах даже на одной платформе. Другая причина кроется в переносимости. Не факт, что ваша программа (или даже её отдельный модуль) никогда не переедут под UNIX. В отличие от Windows, UNIX существует на большом зоопарке платформ. Некоторые из них имеют big-endian представления чисел (первым идёт старший байт). Если на такой платформе сохранить int в файл как есть, а затем прочитать этот файл на Intel-платформе, то мы получим совершенно другое число. Например (пусть размер int будет 32 бита), если на big-endian сохранили 0x12345678, то в little-endian прочитаем 0x78563412.
Для большинства эти детали не существенны, так как не так уж и много программистов (надо признаться, и я в том числе) пишут сразу для нескольких платформ. Но, по крайней мере, задуматься о потенциальных проблемах переносимости надо.
Как же сохранять данные в файл, чтобы и файл, и программа его читающая были переносимы? Ответ уже был в этом топике: сохранять всё в xml или другом текстовом файле. Однако, если объём данных велик, и от двоичных данных никуда не деться, то сохранять все данные следует побайтно. Пример сохранения 32-битного int (предполагаем, что система, где char имеет размер, не равный 8 бит, нам не попадётся):

#include const char filename[] = "file.dat"; void read_int(FILE* f, int* d) < unsigned char buf[4]; unsigned char* p = buf; fread(buf, sizeof(buf), 1, f); // portable *d = *p++; *d += *p++ // fread(d, sizeof(*d), 1, f); // not portable > // read_int void write_int(FILE* f, int d) < unsigned char buf[4]; unsigned char* p = buf; *p++ = d & 0xff; *p++ = (d >> 8) & 0xff; *p++ = (d >> 16) & 0xff; *p = (d >> 24) & 0xff; fwrite(buf, sizeof(buf), 1, f); // portable // fwrite(&d, sizeof(d), 1, f); // not portable > // write_in void help() < fprintf(stderr, "Usage: fileio \n"); exit(1); > // help() int main(int argc, char *argv[]) < const int data = 0x12345678; FILE* fi; FILE* fo; int tmp; char err_msg[255]; if (argc != 2) help(); if (! strcmp(argv[1], "w")) < fo = fopen(filename, "w"); if (! fo) < sprintf(err_msg, "Can not open file '%s'", filename); perror(err_msg); exit(1); > write_int(fo, data); fclose(fo); > else if (! strcmp(argv[1], "r")) < fo = fopen(filename, "r"); if (! fo) < sprintf(err_msg, "Can not open file '%s'", filename); perror(err_msg); exit(1); > read_int(fo, &tmp); fclose(fo); printf("Readed %#08x. Must be %#08x\n", tmp, data); > else help(); return 0; > // main()

Если гложут вопросы быстродействия, особенно в свете того, что big-endian систем не много и ради этой редкости мы замедляем считывание файлов, то необходимо ввести условную компиляцию: на little-endian системе читать int целиком, на big-endian – побайтно. Опять же, нельзя забывать про отличия размера int на разных платформах.
Хочу отметить, что я далеко не гуру в этом вопросе, и все мои замечания основаны лишь на изучении и портировании Open source ПО на компьютер RM200 (RISC-процессор R4000 (big-endian), ОС SINIX).

Всего Вам
Андрей
Re[2]: Запись и чтение структур в/из файл(а)

От: MaximE
Дата: 06.06.05 07:20
Оценка:

[]

> Как же сохранять данные в файл, чтобы и файл, и программа его читающая были переносимы? Ответ уже был в этом топике: сохранять всё в xml или другом текстовом файле. Однако, если объём данных велик, и от двоичных данных никуда не деться, то сохранять все данные следует побайтно. Пример сохранения 32-битного int (предполагаем, что система, где char имеет размер, не равный 8 бит, нам не попадётся):

Автор: MaximE
Дата: 02.04.05
Автор: MaximE
Дата: 06.04.05


Maxim Yegorushkin

Как записать структуру в файл на языке C++?

Нужно создать приложение которое бы записывала структуру в файл и выводило из файла на экран.
Попытался это реализовать.
Но к сожалению не записывает всю структура в файл. Или некорректно записывает.

Вот сам код который я пытался реализовать:

#include "stdafx.h" #include "string.h" #include "stdio.h" #include #include using namespace std; void inputf(ifstream &f, char a[300], char b[300], char c[300], char d[300]); void outputf1(ofstream &f, char a[300], char b[300], char c[300], char s[40]); void main() // Основная функция < int c; setlocale(LC_ALL, "Russian"); cout > c; if (c == 2) < int const N = 3; int i,j=0; struct vvod < char fam[300]; char id[300]; char number[300]; >; vvod v[N]; for (i = 0; i < N; i++) < cout > v[i].fam; cout > v[i].id; cout > v[i].number; > ofstream f1; for (i = 0; i < N; i++) < outputf1(f1, v[i].fam, v[i].id, v[i].number, "writer.txt"); >> else if (c == 1) < char str[40];//Строковая переменная (для пути к файлу) cout > str; char v[900]; char q[300]; char w[300]; char e[300]; ifstream f; inputf(f,str,q,w,e); > > void outputf1(ofstream &f, char a[300], char b[300], char c[300], char s[40])//Функция для записи < f.open(s);//Открываем файл //Проверка успешности открытия файла: if (f.fail()) < cout f void inputf(ifstream &f, char a[300],char b[300], char c[300],char d[300] )//Функция для чтения < f.open(a);//Открываем файл //Проверка успешности открытия файла: if (f.fail()) < cout f >> b;//Читаем переменную из файла f >> c; f >> d; cout 

Подскажите где накосячил.

  • Вопрос задан более трёх лет назад
  • 3285 просмотров

C++. Примеры использования средств C++ для работы с файлами

Примеры использования средств C++ для работы с файлами

В теме приводятся примеры использования файловой системы C++ для:

  • чтения информации из файлов;
  • записи информации в файлы.

Поиск на других ресурсах:

1. Функция, читающая строки из клавиатуры и записывающая их в файл
#include #include using namespace std; // Функция читает строки из клавиатуры и записывает их в файл void Example1(const char* filename) < ofstream os(filename); // текстовый файл для вывода // проверка, открыт ли файл if (!os) < cout "Cannot open the file to output. \n"; return; > char str[80]; cout "Save the lines to HDD. Enter ! to stop." do < cout ":"; // чтение строки с использоанием пробелов между словами cin.getline(str, 80); os // записать в файл строку str > while (*str != '!'); // конец ввода строк - ! os.close(); // закрыть файл return; > void main() < Example1("myfile.txt"); >

После вызова функции Example1() будет создан файл «myfile.txt» , в котором будут записаны строки, введенные с клавиатуры.

Результат работи программы:

Save the lines to HDD. Enter ! to stop. :Hello world! :bestprog.net :Working with files in C++ :!
2. Функция, которая читает текстовый файл и выводит его содержимое на экран

Функция Example2() читает содержимое файла filename , имя которого есть входящим параметром функции.

#include #include using namespace std; // Функция, которая читает файл filename и выводит его на экран // Используется класс ifstream для чтения файла bool Example2(const char * filename) < // создать экземпляр класса ifstream is(filename); // открыть файл в конструкторе // если файл не открыт, то выход с кодом false if (!is) return false; // чтение строк в цикле while char str[100]; // буфер для чтения одной строки while (is) // если is ненулевое, то еще не конец файла < is.getline(str, 100); // прочитать строку из файла в буфер str cout // вывести на екран > is.close(); // закрыть файл return true; > void main() < Example2("myfile.txt"); >

Результат работи программы отображает содержимое файла «myfile.txt» , созданного в п.1 этой темы

Hello world! bestprog.net Working with files in C++ !
3. Пример бесформатного ввода/вывода. Копирование одного файла в другой

В примере реализована функция Example3() , которая выполняет копирование файлов в двоичном (бинарном) формате. Функция получает два параметра. Первый параметр типа const char* есть имя файла-источника. Второй параметр типа const char* есть имя файла-назначения.
Функция реализует посимвольное копирование. Для получения символа из файла-источника используется функция get() .

#include #include using namespace std; // Бесформатный ввод/вывод, копирование одного файла в другой // Функция читает файл readFile и записывает его в файл writeFile // использует функцию get() для чтения bool Example3(const char * readFile, const char * writeFile) < // создать экземпляры классов ifstream, ofstream ifstream rf(readFile, ios::in | ios::binary); // файл-источник (чтение) // проверка, открыт ли файл-источник if (!rf) < cout "Cannot open source file." return false; > // файл-назначение (запись) ofstream wf(writeFile, ios::out | ios::binary); // проверка, открыт ли файл-назначение if (!wf) < rf.close(); // закрыть файл-источник cout "Cannot open the files." return false; > char sym; // цикл посимвольного чтения while (rf) < rf.get(sym); // считать из rf => sym if (rf) wf // записать sym => wf > cout "Copy result: OK!" // закрыть оба файла wf.close(); >

Вызов функции Example3() из функции main() может быть следующим:

void main() < Example3("myfile.txt", "myfile2.txt"); >

После выполнения функции Example3() будет создан файл «myfile2.txt» , который будет копией файла «myfile.txt» .

4. Пример бесформатного ввода/вывода. Копирование одного файла в другой. Функция put()
#include #include using namespace std; // То же, что и Example3(), только для записи использует функцию put() bool Example4(const char * readFile, const char * writeFile) < ifstream rf(readFile, ios::in | ios::binary); // проверка, открыт ли файл if (!rf.is_open()) return false; ofstream wf(writeFile, ios::out | ios::binary); // проверка, открыт ли файл if (!wf.is_open()) < rf.close(); // закрыть ранее открытый файл rf return false; > char sym; // цикл посимвольного чтения while (rf) < rf.get(sym); // считать из rf => sym if (rf) wf.put(sym); // записать sym => wf > rf.close(); // закрыть оба файла wf.close(); > void main() < Example4("myfile.txt", "myfile2.txt"); >
5. Пример функции записывающей структурную переменную в файл

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

Реализована функция Example5() , которая выполняет запись структурной переменной типа BOOK в файл, имя которого есть входящим параметром. Функция Example5() использует функцию write() для записи. Файл открывается в двоичном формате ( ios::binary ).

#include #include #include using namespace std; // Функция, которая записывает структуру типа BOOK в файл, // использует функцию write() struct BOOK < char title[100]; // название книги char author[70]; // автор int year; // год выпуска float price; // стоимость книги >; bool Example5(const char * filename) < // создать структуру BOOK B; strcpy_s(B.title, "Title of book"); strcpy_s(B.author, "Authof of book"); B.year = 2000; B.price = 12.65f; // создать экземпляр файла в двоичном формате (ios::binary) ofstream outFile(filename, ios::out | ios::binary); if (!outFile) return false; // запись структурной переменной B в файл outFile.write((char*)&B, sizeof(BOOK)); outFile.close(); // закрыть файл return true; > void main() < Example5("myfile3.txt"); >
6. Пример чтения структурной переменной из файла

Данный пример есть продолжением предыдущего примера из пункта 5. В примере в функции Example6() заполняется значение структурной переменной типа BOOK . Полученное значение формируется как входящий параметр-ссылка на тип BOOK . Также функция получает параметром имя файла для чтения. Для чтения структурной переменной используется функция read() .

Результат работы программы

Array is written Read the array. Array C: Title = Title-01, Author = Author-01, Year = 2005, Price = 100.95 Title = Title-02, Author = Author-02, Year = 2008, Price = 90.25 Title = Title-03, Author = Author-03, Year = 2002, Price = 180.5
8. Пример записи/чтения массива чисел типа double
  • запись в файл массива M чисел типа double функцией write() ;
  • чтение из файла массива чисел типу double функцией read() .

Файл открывается в двоичном формате.

#include > #include using namespace std; // использование функций read(), write() для записи/чтения массива чисел bool Example8(const char * filename) < double M[] = < 2.44, 3.85, -3.23, 11.85, 3.38 >; // массив чисел int i; int n = 5; // количество элементов в массиве M // 1. Запись массива в файл // 1.1. Создать экземпляр outF, связанный с файлом filename ofstream outF(filename, ios::out | ios::binary); // для записи, двоичный формат // 1.2. Проверка открытия файла if (!outF) < cout "Error. Cannot open the file."; return false; > // 1.3. Записать количество элементов в массиве M outF.write((char*)&n, sizeof(int)); // 1.4. Записать весь массив в файл outF.write((char*)&M, sizeof(double)*n); outF.close(); // закрыть файл // 2. Чтение данных из файла filename в массив M2 double M2[5]; int n2; // 2.1. Открыть файл для чтения ifstream inF(filename, ios::in | ios::binary); // 2.2. Проверка, открыт ли файл? if (!inF) < cout "Error. Cannot open file."; return false; > // 2.3. Прочитать количество элементов в массиве inF.read((char*)&n2, sizeof(int)); // 2.4. Считать данные из файла в массив M2 inF.read((char*)&M2, sizeof(double)*n2); inF.close(); // закрыть файл // 2.5. Вывести массив M2 на экран cout "Array M2:\n"; for (i = 0; i < n2; i++) cout << M2[i] " "; cout return true; > void main() < Example8("file8.bin"); >

Результат работи программы:

Array M2: 2.44 3.85 -3.23 11.85 3.38
9. Пример чтения из файла строк. Функция getline()

В функции Example9() реализуется построчное чтение из файла с помощью функции getline() . Имя файла задается входящим параметром filename . Строки в файле состоят из набора слов, разделенных символом «пробел».

#include #include using namespace std; // Чтение из файла. Функция getline() bool Example9(const char* filename) < ifstream inputFile(filename); char buffer[255]; // буфер для сохранения одной строки if (!inputFile) < cout "Error. Cannot open file"; return false; > // цикл чтения строк из файла while (inputFile) < inputFile.getline(buffer, 255); if (inputFile) cout // вывод прочитанной строки на экран > inputFile.close(); return true; >
10. Пример чтения строк из файла. Функции getline() + eof()

В примере реализована функция Example10() , которая выполняет чтение строк из файла. Файл открывается в текстовом формате. Имя файла задается входящим параметром функции. Определение конца файла выполняется с помощью функции eof() .

#include #include using namespace std; // чтение из файла. Функции getline()+eof() bool Example10(const char* filename) < // создать экземпляр файла filename ifstream inputFile(filename, ios::in); if (!inputFile) return false; char buffer[255]; // буфер для сохранения одной строки // цикл чтения строк файла // строки читаются до тех пор, пока не будет достигнут конец файла while (!inputFile.eof()) < inputFile.getline(buffer, 255); if (inputFile) cout inputFile.close(); >

Связанные темы

Как записать и считать структуру в файл на СИ

Всем добрый вечер, такая проблема, записываю структуру в файл, но при следующем запуске и чтении из файла, программа перестает работать. Также при удаление строчки 114 и 115 программа перестает работать, может кто подсказать почему?

#include #include #include #include using namespace std; typedef struct _date < int num; char* month; int year; >date; typedef struct _fio < char* fam; //Фамилия char* name; //Имя char* father; //отчество >fio; struct _deposid < int countName; fio client; date date; double sum; >; // Функция вывода счета void printClient(_deposid &client) < cout void sumLarge(_deposid *clients, int thisClient, int needSum, int countSum) < for (int i = 0; i < thisClient; i++ ) < if (clients[i].sum >needSum) < printClient(clients[i]); countSum++; >> if (countSum == 0) < cout countSum = 0; > void printNameLastname(_deposid *clients, int thisClient, char *firstname, char *lastname, char *father, int countSum) < for (int i = 0; i < thisClient; i++ ) < if (strcmp(clients[i].client.name, firstname) == 0 && strcmp(clients[i].client.fam, lastname) == 0 && strcmp(clients[i].client.father, father) == 0) < printClient(clients[i]); countSum++; >> if (countSum == 0) < cout countSum = 0; > // Функция создания нового клиента void newClient(_deposid &client) < char *userLastname = new char[100], *userFirstname = new char[100], *userFather = new char[100], *userMonth = new char[100]; // Ввод данных cout > userFirstname; client.client.name = new char[strlen(userFirstname)+1]; strcpy(client.client.name, userFirstname); cout > userLastname; client.client.fam = new char[strlen(userLastname)+1]; strcpy(client.client.fam, userLastname); cout > userFather; client.client.father = new char[strlen(userFather)+1]; strcpy(client.client.father, userFather); cout > client.date.num; cout > userMonth; client.date.month = new char[strlen(userMonth)+1]; strcpy(client.date.month, userMonth); cout > client.date.year; cout > client.sum; // Очистка памяти delete [] userLastname; delete [] userFirstname; > int main() < char *lastname = new char[100], *firstname = new char[100], *father = new char[100]; int n, thisClient = 0, numberFunction = 0, needSum, countSum = 0; _deposid *clients; char c; FILE *fp; fp=fopen("t.txt", "r+"); if (fp==NULL) < fclose(fp); fp=fopen("t.txt", "w+"); cout > n; clients = new _deposid[n]; // Создание массива структур > else < while((c = fgetc(fp)) != EOF) // При удалении этой и строчки ниже программа вообще не запускается putchar(c); while(fread(clients, sizeof(_deposid),1,fp)); // fputs("lol", fp); // fclose(fp); >cout > numberFunction; switch (numberFunction) < case 1: if (thisClient == n) < cout else < clients[thisClient].countName = thisClient + 1; newClient(clients[thisClient]); cout break; case 2: cout break; case 3: // Вывод счетов с суммой большей заданной cout > needSum; cout > firstname; cout > lastname; cout > father; cout > > 

Вот задание

Отслеживать
задан 16 мая 2022 в 11:18
егор виктуров егор виктуров
3 2 2 бронзовых знака

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

В принципе всё просто. Вы в файл сохраняете не все данные.

 case 5: cout  

Когда вы так пишете, в файл сохраняется сама структура. Т.е. в файл сохраняются не текстовые данные, кот. вы записывали в выделяемые через new буферы, а просто значение указателей char* month; и char* fam; char* name; char* father; . Для примера, проверьте значение sizeof(_deposid) - в размере структуры не будет размера того текста (фамилии, имени, отчества, названия месяца), которые вы вводили с клавиатуры.
А потом Вы загружаете из файла значение указателей, которые указывают в "никуда". Вам нужно написать свою функцию вывода Вашей структуры в файл. И свою функцию загрузки структуры из файла.
Существуют уже готовые библиотеки сериализации (вывода в поток и загрузки из потоков) объектов. Но для этой задачи проще написать свои функции.
Совет - каждое поле пишите отдельной строкой и считывайте построчно - так будет проще.
Ну и вот этот кусок:

 fp=fopen("t.txt", "r+"); if (fp==NULL) < clients = new _deposid[n]; // Создание массива структур >else < while((c = fgetc(fp)) != EOF) // При удалении этой и строчки ниже программа вообще не запускается putchar(c); while(fread(clients, sizeof(_deposid),1,fp)); 

Как правильно написал @JohnDoe выделение памяти под массив структур делается только если файла не существует. Если он существует, память под массив не выделяется. И дальше у Вас 2 ошибки, первая из которых не дает состояться второй. Вторая ошибка - запись данных в невыделенную область памяти:

fread(clients, sizeof(_deposid),1,fp) 

Здесь для clients память не выделена! А Вы пытаетесь записать туда что-то!
А первая ошибка не дает случиться второй - вот этими строками вы считываете весь файл.

while((c = fgetc(fp)) != EOF) putchar(c); 

Дескриптор файла указывает на конец файла. Функция fread() не может ничего считать из файла и поэтому ничего не записывает в невыделенную память.
По вашей логике при записи массива структур в файл вам нужно сначала записать туда количество объектов в массиве, а потом - сами объекты. И считывать в таком же порядке:

  • считать количество объектов,
  • выделить под них память,
  • считать сами объекты
    Ещё один момент:
void newClient(_deposid &client) < char *userLastname = new char[100], *userFirstname = new char[100], *userFather = new char[100], *userMonth = new char[100]; . delete [] userLastname; delete [] userFirstname; 

Выделили 4 массива, а освободили только 2. А в main() выделили и вообще не освободили. И зачем выделение через new() , если вы знаете размер буферов? Только чтобы память на куче была выделена? Стек выдержит ваши 400 байт, сделайте проще:

void newClient(_deposid &client)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *