З роботи з великими даними з файлу. Читання та запис файлу. Клас FileStream

Теги: Текстові файли, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, буферизований потік, небуферизований потік.

Робота з текстовими файлами

Робота з текстовим файлом схожа на роботу з консоллю: за допомогою функцій форматованого введення ми зберігаємо дані у файл, за допомогою функцій форматованого виводу зчитуємо дані з файлу. Є безліч нюансів, які ми розглянемо пізніше. Основні операції, які необхідно зробити, це

  • 1. Відкрити файл, щоб до нього можна було звертатися. Відповідно, відкривати можна для читання, запису, читання та запису, переписування або запису в кінець файлу і т.п. Коли ви відкриваєте файл, може також статися купа помилок - файлу може не існувати, це може бути файл не того типу, у вас може не мати права на роботу з файлом і т.д. Все це потрібно враховувати.
  • 2. Безпосередньо робота з файлом - запис та читання. Тут також слід пам'ятати, що ми працюємо не з пам'яттю з довільним доступом, а з буферизованим потоком, що додає специфіку.
  • 3. Закрити файл. Так як файл є зовнішнім по відношенню до програми ресурсом, то якщо його не закрити, він продовжить висіти в пам'яті, можливо, навіть після закриття програми (наприклад, не можна буде видалити відкритий файл або внести зміни і т.п.). Крім того, іноді необхідно не закривати, а "перевідкривати" файл для того, щоб, наприклад, змінити режим доступу.

Крім того, існує ряд завдань, коли нам не потрібно звертатися до вмісту файлу: перейменування, переміщення, копіювання і т.д. На жаль, у стандарті немає опису функцій для цих потреб. Вони, безумовно, є кожної з реалізацій компілятора. Зчитування вмісту каталогу (папки, директорії) – це також звернення до файлу, тому що папка сама собою є файлом з метаінформацією.

Іноді необхідно виконувати деякі допоміжні операції: переміститися в потрібне місце для файлу, запам'ятати поточне положення, визначити довжину файлу і т.д.

Для роботи з файлом потрібний об'єкт FILE. Цей об'єкт зберігає ідентифікатор файлового потоку та інформацію, яка потрібна, щоб ним керувати, включаючи вказівник на його буфер, індикатор позиції у файлі та індикатори стану.

Об'єкт FILE сам по собі є структурою, але до його полів не повинно бути доступу. Програма, що переноситься, повинна працювати з файлом як з абстрактним об'єктом, що дозволяє отримати доступ до файлового потоку.

Створення та виділення пам'яті під об'єкт типу FILE здійснюється за допомогою функції fopen або tmpfile (є й інші, але ми зупинимося лише на цих).

Функція fopen відкриває файл. Вона отримує два аргументи – рядок з адресою файлу та рядок із режимом доступу до файлу. Ім'я файлу може бути як абсолютним, і відносним. fopen повертає покажчик на об'єкт FILE, за допомогою якого можна здійснювати доступ до файлу.

FILE * fopen (const char * filename, const char * mode);

Наприклад, відкриємо файл і запишемо в нього Hello World

#include #include #include void main() ( //За допомогою змінної file будемо здійснювати доступ до файлу FILE *file; //Відкриваємо текстовий файл з правами на запис file = fopen("C:/c/test.txt", "w+t") //Пишемо у файл fprintf(file, "Hello, World!");// Закриваємо файл fclose(file); getch();

Функція fopen сама виділяє пам'ять під об'єкт, очищення проводиться функцією fclose. Закривати файл обов'язково, самостійно не закриється.

Функція fopen може відкривати файл у текстовому чи бінарному режимі. За промовчанням використовується текстовий. Режим доступу може бути наступним

Установки доступу до файлу.
Тип Опис
r Читання. Файл має існувати.
w Запис нового файлу. Якщо файл з таким ім'ям вже існує, його вміст буде втрачено.
a Запис у кінець файлу. Операції позиціонування (fseek, fsetpos, frewind) ігноруються. Файл створюється, а то й існував.
r+ Читання та оновлення. Можна як читати, і писати. Файл має існувати.
w+ Запис та оновлення. Створюється новий файл. Якщо файл з таким ім'ям вже існує, його вміст буде втрачено. Можна як писати, і читати.
a+ Запис у кінець та оновлення. Операції позиціонування працюють лише читання, для запису ігноруються. Якщо файл не існував, буде створено новий.

Якщо потрібно відкрити файл у бінарному режимі, то в кінець рядка додається буква b, наприклад “rb”, “wb”, “ab”, або для змішаного режиму “ab+”, “wb+”, “ab+”. Замість b можна додавати букву t, тоді файл відкриватиметься у текстовому режимі. Це від реалізації. У новому стандарті си (2011) літера x означає, що функція fopen має завершитися з помилкою, якщо файл вже існує. Доповнимо нашу стару програму: заново відкриємо файл і вважаємо, що ми туди записали.

#include #include #include void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); fclose(file); file = fopen("C:/c/test.txt", "r"); fgets(buffer, 127, файл); printf("%s", buffer); fclose(file);

Замість функції fgets можна було використовувати fscanf, але слід пам'ятати, що вона може вважати рядок лише до першого пробілу.
fscanf(file, "%127s", buffer);

Також, замість того, щоб відкривати та закривати файл, можна скористатися функцією freopen, яка «перевідкриває» файл з новими правами доступу.

#include #include #include void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); freopen("C:/ c/test.txt", "r", файл); fgets(buffer, 127, файл); printf("%s", buffer); fclose(file);

Функції fprintf і fscanf відрізняються від printf і scanf тільки тим, що приймають в якості першого аргументу покажчик на FILE, який вони будуть виводити або з якого вони будуть читати дані. Тут варто відразу додати, що функції printf і scanf можуть бути без проблем замінені функціями fprintf і fscanf. У ОС (ми розглядаємо найпоширеніші та найадекватніші операційні системи) існує три стандартні потоки: стандартний потік виведення stdout, стандартний потік введення stdin і стандартний потік виведення помилок stderr. Вони автоматично відкриваються під час запуску програми та пов'язані з консоллю. приклад

#include #include #include void main() ( int a, b; fprintf(stdout, "Enter two numbers\n"); fscanf(stdin, "%d", &a); fscanf(stdin, "%d", &b); == 0) ( fprintf(stderr, "Error: divide by zero"); ) else ( fprintf(stdout, "%.3f", (float) a / (float) b); ) getch(); )

Помилка відкриття файлу

Якщо виклик функції fopen пройшов невдало, вона поверне NULL. Помилки під час роботи з файлами зустрічаються досить часто, тому щоразу, коли ми відкриваємо файл, необхідно перевіряти результат роботи

#include #include #include #define ERROR_OPEN_FILE -3 void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); if (file == NULL) ( printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); ) fprintf(file, "Hello, World!"); = NULL) ( printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); ) fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch() ; )

Проблему викликає випадок, коли відкривається відразу кілька файлів: якщо один з них не можна відкрити, інші також повинні бути закриті

FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) ( printf("Error opening file %s", INPUT_FILE); getch(); exit(3); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf("Error opening file %s", OUTPUT_FILE); getch(); if (inputFile != NULL) ( fclose(inputFile); ) exit(4); ) ...

У простих випадках можна діяти в лоб, як у попередньому шматку коду. У більш складних випадках використовуються методи, що підміняють RAII із С++: обгортки, або особливості компілятора (cleanup GCC) і т.п.

Буферизація даних

Як говорилося раніше, коли ми виводимо дані, вони спочатку поміщаються в буфер. Очищення буфера здійснюється

  • 1) Якщо він заповнений
  • 2) Якщо потік закривається
  • 3) Якщо ми явно вказуємо, що необхідно очистити буфер (тут також є винятки:)).
  • 4) Також очищається, якщо програма завершилася успішно. Разом з цим закриваються всі файли. У разі помилки виконання цього може статися.

Форсувати вивантаження буфера можна за допомогою функції fflush(File *). Розглянемо два приклади – з очищенням та без.

#include #include #include void main() ( FILE *file; char c; file = fopen("C:/c/test.txt", "w"); do ( c = getch(); );fprintf(stdout, "%c", c); //fflush(file); ) while(c != "q"); fclose(file);

Розкоментуйте виклик fflush. Під час виконання відкрийте текстовий файл та подивіться на поведінку.

Буфер файлу можна призначити самостійно, задавши розмір. Робиться це за допомогою функції

Void setbuf (FILE * stream, char * buffer);

яка приймає вже відкритий FILE та покажчик на новий буфер. Розмір нового буфера повинен бути не меншим ніж BUFSIZ (наприклад, на поточній робочій станції BUFSIZ дорівнює 512 байт). Якщо передати як буфер NULL, то потік стане небуферизованим. Можна також скористатися функцією

Int setvbuf (FILE * stream, char * buffer, int mode, size_t size);

яка приймає буфер довільного розміру size. Режим mode може приймати такі значення

  • _IOFBF- Повна буферизація. Дані записуються у файл, коли він заповнюється. На зчитування буфер вважається заповненим, коли запитується операція введення і буфер порожній.
  • _IOLBF- Лінійна буферизація. Дані записуються у файл, коли він заповнюється, або коли зустрічається символ нового рядка. На зчитування буфер заповнюється до символу нового рядка, коли запитується операція введення і буфер порожній.
  • _IONBF- Без буферизації. У цьому випадку параметри size та buffer ігноруються.
У разі успішного виконання функція повертає 0.

Приклад: поставимо свій буфер і подивимося, як здійснюється читання з файлу. Нехай файл короткий (щось типу Hello, World!), і зчитуємо ми його посимвольно

#include #include #include void main() ( FILE *input = NULL; char c; char buffer = (0); input = fopen("D:/c/text.txt", "rt"); setbuf(input, buffer); while ( !feof(input)) ( c = fgetc(input); printf("%c\n", c); printf("%s\n", buffer); _getch(); ) fclose(input); )

Видно, що дані вже знаходяться у буфері. Зчитування посимвольно провадиться вже з буфера.

feof

Функція int feof (FILE * stream); повертає істину, якщо кінець файлу досягнуто. Функцію зручно використовувати, коли потрібно пройти весь файл від початку до кінця. Нехай є файл із текстовим вмістом text.txt. Вважаємо посимвольно файл та виведемо на екран.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); ) while (!feof(input)) ( c = fgetc(input); fprintf(stdout, "%c", c); ) fclose(input); _getch(); )

Все б нічого, тільки функція feof працює неправильно... Це пов'язано з тим, що поняття "кінець файлу" не визначено. При використанні feof часто виникає помилка, коли останні лічені дані виводяться двічі. Це пов'язано з тим, що дані записуються в буфер введення, останнє зчитування відбувається з помилкою і функція повертає старе зчитане значення.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); ) while (!feof(input)) ( fscanf(input, "%c", &c); fprintf(stdout, "%c", c); ) fclose(input); _getch(); )

Цей приклад спрацює з помилкою (скоріше за все) та виведе останній символ файлу двічі.

Рішення не використовувати feof. Наприклад, зберігати загальну кількість записів або використовувати той факт, що функції fscanf та ін зазвичай повертають число вірно лічених і зіставлених значень.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); ) while (fscanf(input, "%c", &c) == 1) ( fprintf(stdout, "%c", c); ) fclose(input); _getch() ; )

Приклади

1. В одному файлі записані два числа – розмірності масиву. Заповнимо другий файл масивом випадкових чисел.

#include #include #include #include //Імена файлів і права доступу #define INPUT_FILE "D:/c/input.txt" #define OUTPUT_FILE "D:/c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" //Максимальне значення для розміру масиву #define MAX_DIMENSION 100 //Помилка при відкритті файлу #define ERROR_OPEN_FILE -3 void main() (FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile == NULL) ( printf("Error opening file %s", INPUT_FILE); getch(); exit(ERROR_OPEN_FILE); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf("Error opening file %s", OUTPUT_FILE); getch(); //Якщо файл для читання вдалося відкрити, то його необхідно закрити if (inputFile != NULL) ( fclose(inputFile); ) exit(ERROR_OPEN_FILE); ) fscanf(inputFile, "%ud %ud", &m, &n), ​​if (m > MAX_DIMENSION) ( m = MAX_DIMENSION; ) if (n > MAX_DIMENSION) ( n = MAX_DIMENSION; ) srand(time(NULL)), for (i = 0; i< n; i++) { for (j = 0; j < m; j++) { fprintf(outputFile, "%8d ", rand()); } fprintf(outputFile, "\n"); } //Закрываем файлы fclose(inputFile); fclose(outputFile); }

2. Користувач копіює файл, у своїй спочатку вибирає режим роботи: файл може виводитися як у консоль, і копіюватися у новий файл.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *origin = NULL; FILE *output = NULL; char filename; int mode; printf("Enter filename: "); scanf("%1023s", filename); (filename, "r"); if (origin == NULL) ( printf("Error opening file %s", filename); getch(); exit(ERROR_FILE_OPEN); ) printf("enter mode: "); scanf( "%d", &mode); if (mode == 1) ( printf("Enter filename: "); scanf("%1023s", filename); output = fopen(filename, "w"); if (output = = NULL) ( printf("Error opening file %s", filename); getch(); fclose(origin); exit(ERROR_FILE_OPEN); ) ) else ( output = stdout; ) while (!feof(origin)) ( fprintf (output, "%c", fgetc(origin)); ) fclose(origin); fclose(output); getch(); )

3. Користувач вводить дані з консолі і вони записуються у файл доти, доки не буде натиснуто клавішу esc. Перевірте програму та подивіться. як вона поводиться у випадку, якщо ви вводите backspace: що виводиться у файл і що виводиться на консоль.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *output = NULL; char c; output = fopen("D:/c/test_output.txt", "w+t"); if (output == NULL) ( printf ("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) for (;;) ( c = _getch(); c, stdout);) fclose(output);

4. У файлі записані цілі числа. Знайти максимальну з них. Скористаємося тим, що функція fscanf повертає кількість чітко прочитаних та зіставлених об'єктів. Щоразу має повертатися число 1.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; hasRead = 1; while (hasRead == 1) ( hasRead = fscanf(input, "%d", &num); if (hasRead != 1) ( continue; ) if (num >

Інше рішення зчитувати числа, доки не дійдемо до кінця файлу.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; while (!feof(input)) ( fscanf(input, "%d", &num); ) ( maxn = num; ) ) printf("max number = %d", maxn); fclose(input); _getch(); )

5. У файлі записані слова: російське слово, табуляція, англійське слово, кілька рядів. Користувач запроваджує англійське слово, необхідно вивести російське.

Файл із перекладом виглядає приблизно так

Сонце sun
олівець pen
кулькова ручка pencil
двері door
вікно windows
стілець chair
крісло armchair

та збережений у кодуванні CP866 (OEM 866). При цьому важливо: остання пара слів також закінчується перекладом рядка.

Алгоритм наступний - зчитуємо рядок з файлу, знаходимо у рядку знак табуляції, підмінюємо знак табуляції нулем, копіюємо російське слово з буфера, копіюємо англійське слово з буфера, перевіряємо на рівність.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; char buffer; char enWord; char ruWord; char usrWord; unsigned index; int length; int wasFound; input = fopen("D:/c/input.txt ", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) printf("enter word: "); fgets(usrWord, 127, stdin );wasFound = 0; while (!feof(input)) ( fgets(buffer, 511, input); length = strlen(buffer); for (index = 0; index< length; index++) { if (buffer == "\t") { buffer = "\0"; break; } } strcpy(ruWord, buffer); strcpy(enWord, &buffer); if (!strcmp(enWord, usrWord)) { wasFound = 1; break; } } if (wasFound) { printf("%s", ruWord); } else { printf("Word not found"); } fclose(input); _getch(); }

6. Підрахувати кількість рядків у файлі. Зчитуватимемо файл посимвольно, рахуючи кількість символів "\n" доти, доки не зустрінемо символ EOF. EOF - це спецсимвол, який вказує на те, що введення закінчено і більше немає даних для читання. Функція повертає негативне значення у разі помилки.
ПРИМІТКА: EOF має тип int, тому потрібно використовувати int для зчитування символів. Крім того, значення EOF не визначено стандартом.

#define _CRT_SECURE_NO_WARNINGS #include #include #include int cntLines(const char *filename) ( int lines = 0; int any; //any типу int, тому що EOF має тип int! FILE *f = fopen(filename, "r"); if (f == NULL) ( return -1; ) do ( any = fgetc(f); //printf("%c", any);//debug if (any == "\n") ( lines++; ) ) while(any != EOF); ​​fclose(f); return lines;

Ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 [email protected] Stepan Sypachev students

Все ще незрозуміло? – пиши запитання на скриньку

Для зручності поводження інформація в пристроях зберігається у вигляді файлів.

Файл - назва область зовнішньої пам'яті, виділена для зберігання масиву даних. Дані, що містяться у файлах, мають найрізноманітніший характер: програми алгоритмічною або машинною мовою; вихідні дані для роботи програм чи результати виконання програм; довільні тексти; графічні зображення тощо.

Каталог (папка, директорія) – іменована сукупність байтів на носії інформації, що містить назву підкаталогів та файлів, використовується у файловій системі для спрощення організації файлів.

Файлова системаназивається функціональна частина операційної системи, що забезпечує виконання операцій над файлами. Прикладами файлових систем є FAT (FAT - File Allocation Table, таблиця розміщення файлів), NTFS, UDF (використовується на компакт-дисках).

Існують три основні версії FAT: FAT12, FAT16 та FAT32. Вони відрізняються розрядністю записів у дискової структурі, тобто. кількістю біт, відведених зберігання номера кластера. FAT12 застосовується переважно для дискет (до 4 кбайт), FAT16 – для дисків малого обсягу, FAT32 – для FLASH-накопичувачів великої ємності (до 32 Гбайт).

Розглянемо структуру файлової системи з прикладу FAT32.

Файлова структура FAT32

Пристрої зовнішньої пам'яті FAT32 мають не байтову, а блокову адресацію. Запис інформації у пристрій зовнішньої пам'яті здійснюється блоками чи секторами.

Сектор – мінімальна одиниця зберігання інформації, що адресується, на зовнішніх запам'ятовуючих пристроях. Як правило, розмір сектора фіксований та становить 512 байт. Для збільшення адресного простору пристроїв зовнішньої пам'яті сектора об'єднують групи, звані кластерами.

Кластер – об'єднання кількох секторів, що може розглядатися як самостійна одиниця, що має певні властивості. Основною властивістю кластера є його розмір, що вимірюється у кількості секторів або кількості байт.

Файлова система FAT32 має таку структуру.

Нумерація кластерів, що використовуються для запису файлів, ведеться з 2. Як правило, кластер №2 використовується кореневим каталогом, а з кластера №3 зберігається масив даних. Сектори, що використовуються для зберігання інформації, представленої вище кореневого каталогу, кластери не об'єднуються.
Мінімальний розмір файлу, який займає на диску, відповідає 1 кластеру.

Завантажувальний сектор починається наступною інформацією:

  • EB 58 90 – безумовний перехід та сигнатура;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 0002 - кількість байт в секторі (зазвичай 512);
  • 1 байт – кількість секторів у кластері;
  • 2 байти – кількість резервних секторів.

Крім того, завантажувальний сектор містить таку важливу інформацію:

  • 0x10 (1 байт) – кількість таблиць FAT (зазвичай 2);
  • 0x20 (4 байти) – кількість секторів на диску;
  • 0x2С (4 байти) – номер кластера кореневого каталогу;
  • 0x47 (11 байт) – мітка тому;
  • 0x1FE (2 байти) – сигнатура завантажувального сектора (55 AA).

Сектор інформації файлової системи містить:

  • 0x00 (4 байти) - сигнатура (52 52 61 41);
  • 0x1E4 (4 байти) - сигнатура (72 72 41 61);
  • 0x1E8 (4 байти) - кількість вільних кластерів, -1 якщо не відомо;
  • 0x1EС (4 байти) – номер останнього записаного кластера;
  • 0x1FE (2 байти) - сигнатура (55 AA).

Таблиця FAT містить інформацію про стан кожного кластера на диску. Молодші 2 байт таблиці FAT зберігають F8 FF FF 0F FF FF FF FF (що відповідає стану кластерів 0 та 1, фізично відсутніх). Далі стан кожного кластера містить номер кластера, в якому продовжується поточний файл або таку інформацію:

  • 00 00 00 00 – кластер вільний;
  • FF FF FF 0F – кінець поточного файлу.
  • 8 байт – ім'я файлу;
  • 3 байти - розширення файлу;

Кореневий каталог містить набір 32-бітових записів інформації про кожен файл, що містять таку інформацію:

У разі роботи з довгими іменами файлів (включаючи російські імена), кодування імені файлу проводиться в системі кодування UTF-16. При цьому для кодування кожного символу відводиться 2 байти. При цьому ім'я файлу записується у вигляді наступної структури:

  • 1 байт послідовності;
  • 10 байт містять молодші 5 символів імені файлу;
  • 1 байт атрибут;
  • 1 байт резервний;
  • 1 байт – контрольна сума імені DOS;
  • 12 байт містять молодші 3 символи імені файлу;
  • 2 байти – номер першого кластера;
  • решта символів довгого імені.

Робота з файлами у мові Сі

Для програміста відкритий файл представляється як послідовність даних, що зчитуються або записуються. При відкритті файлу з ним зв'язується потік введення-виводу. Інформація, що виводиться записується в потік, інформація, що вводиться, зчитується з потоку.

Коли потік відкривається для введення-виведення, він зв'язується зі стандартною структурою типу FILE , яка визначена stdio.h . Структура FILE містить потрібну інформацію про файл.

Відкриття файлу здійснюється за допомогою функції fopen(), яка повертає покажчик на структуру типу FILE, який можна використовувати для подальших операцій із файлом.

FILE *fopen(name, type);


name – ім'я файлу, що відкривається (включаючи шлях),
type — покажчик на рядок символів, що визначають спосіб доступу до файлу:
  • "r" – відкрити файл для читання (файл повинен існувати);
  • "w" – відкрити порожній файл для запису; якщо файл існує, його вміст втрачається;
  • "a" - відкрити файл для запису на кінець (для додавання); файл створюється, якщо він не існує;
  • "r+" - відкрити файл для читання та запису (файл повинен існувати);
  • "w+" - відкрити порожній файл для читання та запису; якщо файл існує, його вміст втрачається;
  • "a+" - відкрити файл для читання та доповнення, якщо файл не існує, він створюється.

Значення, що повертається - покажчик на відкритий потік. Якщо виявлено помилку, то повертається значення NULL .

Функція fclose() закриває потоки або потоки, пов'язані з відкритими за допомогою функції fopen() файлами. Потік, що закривається визначається аргументом функції fclose() .

Значення, що повертається: значення 0, якщо потік успішно закритий; константа EOF, якщо сталася помилка.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include
int main() (
FILE * fp;
char name = "my.txt";
if ((fp = fopen(name, "r")) == NULL )
{
printf( "Не вдалося відкрити файл");
getchar();
return 0;
}
// Відкрити файл вдалося
... // необхідні дії над даними
fclose(fp);
getchar();
return 0;
}

Читання символу з файлу:

char fgetc (потік);


Аргументом функції є покажчик на потік типу FILE. Функція повертає код прочитаного символу. Якщо досягнуто кінець файлу або виникла помилка, повертається константа EOF .

Запис символу у файл:

fputc (символ, потік);

Аргументами функції є символ і покажчик на потік типу FILE. Функція повертає код прочитаного символу.

Функції fscanf() і fprintf() аналогічні до функцій scanf() і printf() , але працюють з файлами даних, і мають перший аргумент - покажчик на файл.

fscanf(потік, "ФорматВведення", аргументи);

Записувати інформацію до текстового файлу ми вже навчилися. – Якщо не навчилися, дивіться минулу статтю. Там розповідається та докладно описано

Але якщо файл вже існує і нам потрібно рахувати з нього інформацію для обробки? На щастя, це теж досить просто. Нагадую, що варіантів для реалізації цього завдання існує кілька, мною описаний лише один. Описаний той, який особисто мені чомусь здається найпростішим для сприйняття.

#include

int main()
{
char s1 //Змінна зчитуватиме рядок
ifstream in (“C:\FromC\myfile.txt”); //Відкриваємо файл для зчитування інформації
in >> s1; //зчитуємо рядок
in .close () //Закриваємо файл

cout<Виводимо значення s1на екран
return 0;
}

Ось найпростіша програма для зчитування першого рядка з текстового файлу, який знаходиться на шляху
C:\FromC\myfile.txt –
Так як це продовження минулої статті, то я вирішив використовувати файл, який ми там створювали. Проблем з цим, напевно, виникнути не повинно.
Але повернемось до коду. Спочатку ми відкриваємо файл для зчитування інформації, для цього використовуємо команду ifstream ,у дужках вказуємо або назву файлу, або шлях до файлу, як зроблено в мене. (“C:\FromC\myfile.txt”);
Коли ми відкрили файл, щоб рахувати щось із нього, ми оголосили одну змінну типу char –
char s1
Тепер нам залишилося лише присвоїти змінної значення рядка з файлу. Це ми робимо командою in
Звертаємо увагу на кутові дужки in >>
Власне, як має бути видно з коментарів до коду програми, то щоб змінна надала зчитуване значення, ми повинні написати її після in >>
in >> s1;

Ніяким особливо складним завданням це не представляється, особливо якщо ви вже чудово освоїли та навчилися використовувати матеріал минулої статті – все абсолютно аналогічно, тільки 2 команди інші

Створення файлу та запис у нього інформації С++

ofstream out (ім'я файлу );
out<< (Записуваний рядок);
out. close ();
=============================

Читання тексту з файлу та виведення тексту на екран C++

ifstream in (Ім'я файлу );
in>> (Зчитуємо рядок);
in. close ();(Закриваємо файл)
============================
Напишемо просту програму, яка зчитуватиме введення з клавіатури тексту та записуватиме його у файл:

#include
#include

int main()
{
\\ 3 майбутні рядки
clrscsr(); //Очищаємо екран

cout<<“Wwedi pervuu stroku” ; cin >>a; endl;
cout<<“Wwedi wtoruu stroku” ; cin >> b; endl;
cout<<“Wwedi tretuu stroku” ; cin >>c; endl;
clrscr(); //

/*Починаємо роботу з файлом*/
ofstream out (“C:\FromC\myfile.txt”); //Відкриваємо файл для запису
out<Записуємо перший рядок
out<Записуємо другий рядок
out<Записуємо третій рядок
out .close(); //Закриваємо файл

//Обнуляємо змінні

for (int i = 0; i<=255 ;i ++)
(a =*“” ; b =*“” ; c =*“” ;)


ifstream in ("C:\FromC\myfile.txt");
in >>a >>b >>c; //Зчитуємо кожну нову сходинку в нову змінну
in .close (); //Закриваємо файл

/* */

for (i = 0 ;a !=*“” ;i ++)
{
if (i >sizeof(a )) break;
cout<

}
cout<<“\n” ; \\

/* */


{
if (i > sizeof(b )) break;
cout<
}
cout<<“\n” ; \\ Перевели курсор на новий рядок

/* */

for (i = 0 ;с !=*“” ;i ++)
{
if (i > sizeof(c )) break;
cout<<с ;
}

return 0;
}
===================

У наведених вище прикладах є один такий ВЕЛИЧЕЗНИЙ нестача. Якщо ми намагатимемося ввести рядок, що містить прогалини, то програма спрацьовуватиме не так, як нам потрібно. Напевно, на цю помилку натрапив не лише я, а й багато інших людей. Тому я залишаю невірно наведений код, щоб було видно, з чим можна зіткнутися.

Оскільки книжок удома немає, я знову почав нишпорити в інтернеті і знайшов багато всякої складної нісенітниці. Але таки якось підібрав вирішення своєї проблеми.
Допомогло те, що читав про те, що coutпідтримує свої способи. І в інтернеті всі поради йдуть на використання функції getlineНа моє щастя, як використовувати цю функцію я знайшов дуже швидко і потім використовував її в коді.
Взагалі варто згадати і описати цю функцію, але поки що я не особливо її розумію, просто розумію, що її потрібно використовувати і розумію як, тому наводжу правильніший приклад нашої програми, що розробляється:

#include
#include

int main()
{
char a, b, c; \\ 3 майбутні рядки
clrscsr(); //Очищаємо екран

/* Вводимо значення для змінних*/

cout<<“Wwedi pervuu stroku” ; cin.getline(a,sizeof(a)); endl;
cout<<“Wwedi wtoruu stroku” ; cin.getline(a,sizeof(b)); endl;
cout<<“Wwedi tretuu stroku” ; cin.getline(a,sizeof(c)); endl;
clrscr(); //Після введення значень очистили екран

/*Починаємо роботу з файлом*/
ofstream out (“C:\FromC\myfile.txt”); //Відкриваємо файл для запису
out<
Записуємо перший рядок
out<Записуємо другий рядок
out<Записуємо третій рядок
out .close(); //Закриваємо файл

//Обнуляємо змінні

for (int i = 0; i<=255 ;i ++)
(a =*“” ; b =*“” ; c=*“” ;)

/*Продовжуємо роботу з файлом*/

if stream in ("C:\FromC\myfile.txt");
in.getline(a,sizeof(a));// а
in.getline(b,sizeof(b));// Зчитуємо рядок у змінну b
in.getline(c,sizeof(c)); // Зчитуємо рядок у змінну c
in .close (); //Закриваємо файл

/* Зчитуємо посимвольно перший рядок та виводимо його на екран */

for (i =0 ;a !=*“” ;i++)
{
if (i >sizeof(a )) break;
cout<

}
cout<<“\n” ; \\ Перевели курсор на новий рядок

/* Зчитуємо посимвольно другий рядок та виводимо його на екран */

for (i =0 ;b !=*“” ;i ++)
{
if (i > sizeof(b )) break;
cout<
}
cout<<“\n” ; \\ Перевели курсор на новий рядок

/* Зчитуємо посимвольно третій рядок та виводимо його на екран */

for (i =0 ;с !=*“” ;i++)
{
if (i>sizeof (c)) break;
cout<<с[i];
}

getch(); \\Очікуємо натискання клавіші Enter
return 0;
}
===================

У цьому матеріалі розібрано приклад посимвольного читання інформації. Так як я не описував роботу зі змінними типу char, то у початківців можуть виникнути деякі незручності сприйняття коду. Просто я не знав, що тип charмає якісь особливості та думав все простіше. Тому деякі незрозумілі моменти наведеної програми можна прочитати у наступній статті робота з charв C++ для початківців

В іншому, наведений приклад, як у C++ рахувати рядки з текстового файлу має бути доступним і цілком зрозумілим. Це зараз не оптимальний варіант реалізації, і я упустив деякі важливі моменти, але так як у нас початок вивчення мови C++, то цього поки що цілком достатньо. Пізніше я, напевно, дійду до втраченого, а зараз треба сприймати тільки найнеобхідніше.

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

Примітка:
break;– Це команда, яка виконує вихід із циклу. У нас якщо лічильник циклу forстає більше ніж оголошений розмір змінної char,то ми примусово виходимо із циклу
!= – це поставлена ​​нами умова. Позначає таку умову нерівність
if(a !=b )- Читається як якщо aне дорівнює b

endl; -Це переведення курсору на новий рядок усередині консолі (наскільки я зрозумів)
Ця команда схожа на "\n"

– порівняння виявлення рівності чи нерівності.

Практичне призначення перерахування – визначення безлічі символічних констант цілого типу, що відрізняються.

Приклад використання змінних типу:

mo = 1, tu, we, th, fr, sa, su) days;

puts(“ Введіть день тижня (від 1 до 7): ”); scanf(“%d”, &t_day);

w_day = su; start = mo;

end = w_day-t_day;

printf(“\n Понеділок - %d-й день тижня, \ зараз %d-й день. \n\

До кінця тижня %d днів (дня). ”, start, t_day, end);

Результат роботи програми: Введіть день тижня (від 1 до 7): 2

Понеділок – 1-й день тижня, зараз 2-й день. До кінця тижня – 5 днів (дня).

18. Файли у мові Сі

Файл – це набір даних, розміщений зовнішньому носії і аналізований у процесі обробки як єдине ціле. У файлах розміщуються дані, які призначені для тривалого зберігання.

Розрізняють два види файлів: текстові та бінарні. Текстові файли є послідовністю ASCII символів і можуть бути переглянуті та відредаговані за допомогою будь-якого текстового редактора.

Бінарні (двійкові) файли є послідовністю даних, структура яких визначається програмно.

У мові Сі є великий набір функцій для роботи з файлами, більшість яких знаходяться в бібліотеках stdio.h та iio.h.

18.1. Відкриття файлу

Кожному файлу надається внутрішнє логічне ім'я, що використовується надалі при зверненні до нього. Логічне ім'я (ідентифікатор файлу) – це

покажчик на файл, тобто. область пам'яті, де міститься вся необхідна інформація про файл. Формат оголошення покажчика на файл наступний:

FILE * покажчик на файл;

FILE – ідентифікатор структурного типу, описаний у стандартній бібліотеці

stdio.h і містить таку інформацію:

type struct (

- Число непрочитаних байт, що залишилися в буфері;

Простий обсяг буфера – 512 байт; як тільки level = 0,

у буфер із файлу читається наступний блок даних;

- Прапор статусу файлу - читання, запис, доповнення;

- Дескриптор файлу, тобто. число, що визначає його но-

unsigned char hold;

- Непереданий знак, тобто. ungetc-символ;

- Розмір внутрішнього проміжного буфера;

unsigned char buffer;

– значення покажчика доступу всередині буфера, тобто.

задає початок буфера, початок рядка або поточне зна-

чення покажчика всередині буфера в залежності від реж-

ма буферизації;

unsigned char *curp;

– поточне значення вказівника для доступу всередині бу-

фера, тобто. задає поточну позицію в буфері для обме-

з програмою;

unsigned istemp;

- Прапор тимчасового файлу;

- Прапор під час роботи з файлом;

) FILE;

Перш ніж розпочати працювати із файлом, тобто. отримати можливість читання чи запису інформації у файл, його потрібно відкрити доступу. Для цього зазвичай використовується функція

FILE* fopen (char* ім'я_ файлу, char* режим);

вона бере зовнішнє уявлення – фізичне ім'я файлу на носії (дискета, вінчестер) і ставить йому у відповідність логічне ім'я.

фізичне ім'я, тобто. ім'я файлу та шлях до нього задається першим параметром

- рядком, наприклад, "a:Mas_dat.dat" - файл з ім'ям Mas_dat.dat, що знаходиться на дискеті, "d:\work\\Sved.txt" - файл з ім'ям Sved.txt, що знаходиться на вінчестері в каталозі work .

Увага! Зворотний сліш (\), як спеціальний символ, у рядку записується двічі.

При успішному відкритті функція fopen повертає покажчик на файл (надалі – покажчик файлу). При помилці повертається NULL. Ця ситуація зазвичай виникає, коли неправильно вказується шлях до файлу, що відкривається. Наприклад, якщо в дисплейному класі нашого університету вказати шлях, заборонений для запису (зазвичай дозволено d:\work\).

Другий параметр – рядок, в якому задається режим доступу до файлу:

w – файл відкривається для запису; якщо файлу із заданим ім'ям немає, він буде створено; якщо такий файл існує, перед відкриттям колишня інформація знищується;

r – файл відкривається лише читання; якщо такого файлу немає, виникає помилка;

a – файл відкривається додавання до кінця нової інформації;

r+ – файл відкривається для редагування даних – можливі запис, і читання інформації;

w+ – те саме, що й для r+;

a+ – те саме, що й для a, лише запис можна виконувати будь-яке місце файла; доступне та читання файлу;

t – файл відкривається у текстовому режимі; b – файл відкривається у двійковому режимі.

Текстовий режим відрізняється від двійкового тим, що при відкритті файлу як текстової пари символів "переклад рядка", "повернення каретки" замінюється на один символ: "переведення рядка" для всіх функцій запису даних у файл, а для всіх функцій виведення символ "переклад рядка" тепер замінюється на два символи: «переклад рядка», «повернення каретки».

За замовчуванням файл відкривається у текстовому режимі. Приклад: FILE * f; - Оголошується покажчик на файл f;

f = fopen ("d:\work\Dat_sp.cpp", "w"); – відкривається для запису файл із логічним ім'ям f, що має фізичне ім'я Dat_sp.cpp, що знаходиться на диску d, у каталозі work; або коротше

FILE *f = fopen ("d:\work\Dat_sp.cpp", "w");

18.2. Закриття файлу

Після роботи з файлом, доступ до нього необхідно закрити. Це виконує функція int fclose (покажчик файлу). Наприклад, із попереднього прикладу файл закривається так: fclose (f);

Для закриття кількох файлів введена функція, оголошена так: void fcloseall (void );

Якщо потрібно змінити режим доступу до файлу, то для цього спочатку необхідно закрити файл, а потім знову його відкрити, але з іншими правами доступу. Для цього використовують стандартну функцію:

FILE * freopen (char * ім'я_файлу, char * режим, FILE * покажчик_файлу);

Ця функція спочатку закриває файл, оголошений вказівником_файлу(як це робить функція fopen ), а потім відкриває файл сименем_файла та правами доступу «режим».

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

FILE * tmpfile (void);

яка створює на диску тимчасовий файл з правами доступу w+b, після завершення роботи програми або після закриття тимчасового файлу він автоматично видаляється.

18.3. Запис – читання інформації

Усі дії з читання-запису даних у файл можна поділити на три групи: операції посимвольного введення-виводу; операції рядкового введення виводу; операції введення-виведення по блоках.

Розглянемо основні функції, що застосовуються у кожній із зазначених трьох груп операцій.

Посимвольне введення-виведення

У функціях посимвольного введення-виводу відбувається прийом одного символу з файлу або передача одного символу файл:

Порядкове введення-виведення

У функціях рядкового введення-виведення відбувається перенесення з файлу або в

Блокове введення-виведення

У функціях блокового введення-виведення робота відбувається з цілими блоками

інформації:

int fread (void*p, intsize,

– зчитує n блоків поsize байт кожен з фай-

int n, FILE *f)

ла f в область пам'яті з вказівником p (необхідно

int fwrite (void*p, intsize,

заздалегідь відвести пам'ять під зчитуваний блок);

– записує n блоків по size байт кожен з об-

int n, FILE *f)

ласті пам'яті з покажчиком p файл f.

Форматоване введення-виведення здійснюється функціями.

До цього під час введення-виведення даних ми працювали зі стандартними потоками - клавіатурою та монітором. Тепер розглянемо, як у мові C реалізовано отримання даних із файлів та запис їх туди. Перед тим, як виконувати ці операції, потрібно відкрити файл та отримати доступ до нього.

У мові програмування C покажчик файл має тип FILE і його оголошення виглядає так:
FILE * myfile;

З іншого боку, функція fopen() відкриває файл за вказаною як перший аргумент адресою в режимі читання ("r"), запису ("w") або додавання ("a") і повертає в програму покажчик на нього. Тому процес відкриття файлу та підключення його до програми виглядає приблизно так:
myfile = fopen ("hello.txt", "r");

При читанні або запису даних у файл звернення до нього здійснюється за допомогою вказівника файлу (в даному випадку, myfile).

Якщо через ті чи інші причини (немає файлу за вказаною адресою, заборонено доступ до нього) функція fopen() не може відкрити файл, то вона повертає NULL. У реальних програмах майже завжди обробляють помилку відкриття файлу у гілці if, ми ж далі опустимо це.

Оголошення функції fopen() міститься в заголовку stdio.h, тому потрібне його підключення. Також у stdio.h оголошено тип-структуру FILE.

Після того, як робота з файлом закінчена, прийнято його закривати, щоб звільнити буфер від даних та з інших причин. Це особливо важливо, якщо після роботи з файлом програма продовжує виконуватись. Розрив зв'язку між зовнішнім файлом та вказівником на нього із програми виконується за допомогою функції fclose() . Як параметр їй передається покажчик на файл:
fclose(myfile);

У програмі можна відкрити не один файл. У такому разі кожен файл повинен бути пов'язаний зі своїм файловим покажчиком. Однак, якщо програма спочатку працює з одним файлом, потім закриває його, то вказівник можна використовувати для відкриття другого файлу.

Читання з текстового файлу та запис до нього

fscanf()

Функція fscanf() аналогічна за змістом функції scanf() , але на відміну від неї здійснює форматоване введення файлу, а не стандартного потоку введення. Функція fscanf() приймає параметри: файловий покажчик, рядок формату, адреси областей пам'яті для запису даних:
fscanf (myfile, "%s%d", str, &a);

Повертає кількість вдало лічених даних чи EOF. Пробіли, символи переходу до нового рядка враховуються як роздільники даних.

Припустимо, у нас є файл, який містить такий опис об'єктів:

Apples 10 23.4 bananas 5 25.0 bread 1 10.3

#include main () (FILE * file; struct food (char name [20]; unsigned qty; float price;); struct food shop [10]; char i = 0; file = fopen ("fscanf.txt", "r" ) , while (fscanf (file, "%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) ( printf ("%s%u%.2f \n ", shop[i].name, shop[i].qty, shop[i].price); i++; )

У разі оголошується структура і масив структур. Кожен рядок із файлу відповідає одному елементу масиву; елемент масиву є структурою, що містить рядкове і два числових поля. За одну ітерацію цикл зчитує один рядок. Коли зустрічається кінець файлу fscanf(), повертає значення EOF і цикл завершується.

fgets()

Функція fgets() аналогічна функції gets() і здійснює рядкове введення з файлу. Один виклик fgets() дозволить прочитати один рядок. При цьому можна прочитати не весь рядок, а лише її частину від початку. Параметри fgets() виглядають таким чином:
fgets (масив_символів, кількість_зчитуваних_символів, покажчик_на_файл)

Наприклад:
fgets (str, 50, myfile)

Такий виклик функції прочитає з файлу, пов'язаного з покажчиком myfile, один рядок тексту повністю, якщо його довжина менше 50 символів з урахуванням символу \n, який функція також збереже в масиві. Останнім (50) елементом масиву str буде символ "\0", доданий fgets() . Якщо рядок виявиться довшим, функція прочитає 49 символів і в кінці запише "\0". У такому разі "\n" у ліченому рядку не утримуватиметься.

#include #define N 80 main () ( FILE * file; char arr [ N] ; file = fopen ("fscanf.txt" , "r" ) ; while (fgets (arr, N, file) != NULL) printf (" %s" , arr) ; printf (" \n "); fclose (file); )

У цій програмі на відміну від попередньої дані зчитуються рядок за рядком масив arr. Коли зчитується наступний рядок, попередній втрачається. Функція fgets() повертає NULL, якщо не може прочитати наступний рядок.

getc() або fgetc()

Функція getc() або fgetc() (працює і те, й інше) дозволяє отримати з файлу черговий один символ.

while ((arr[ i] = fgetc (file) ) != EOF) ( if (arr [ i] == " \n ") ( arr [ i] = " \0 " ; printf ("%s \n ", arr); i = 0; ) else i++; ) arr [i] = " \0 " ; printf ("%s \n ", arr);

Наведений як приклад код виводить дані із файлу на екран.

Запис до текстового файлу

Також як і введення, виведення файл може бути різним.

  • Форматований висновок. Функція fprintf (файловий_покажчик, рядок_формату, змінні) .
  • Посточный висновок. Функція fputs (рядок, файловий_покажчик) .
  • Посимвольне виведення. Функція fputc() або putc(символ, файловий_покажчик) .

Нижче наводяться приклади коду, в яких використовуються три способи виведення даних у файл.

Запис у кожний рядок файлу полів однієї структури:

file = fopen ("fprintf.txt", "w"); while (scanf ("%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) ( fprintf (file, " %s %u %.2f \n ", shop[i].name, shop[i].qty, shop[i].price); i++; )

Порядковий висновок у файл (fputs() , на відміну puts() сама не поміщає в кінці рядка "\n"):

while (gets (arr)! = NULL) (fputs (arr, file); fputs (" \n ", file); )

Приклад посимвольного висновку:

while ((i = getchar ())! = EOF) putc (i, file);

Читання з двійкового файлу та запис до нього

З файлом можна працювати не як із послідовністю символів, а як із послідовністю байтів. В принципі, з нетекстовими файлами працювати по-іншому неможливо. Однак так можна читати і писати і текстові файли. Перевага такого способу доступу до файлу полягає у швидкості читання-запису: за одне звернення можна рахувати/записати суттєвий блок інформації.

При відкритті файлу для двійкового доступу другим параметром функції fopen() є рядок "rb" або "wb".

Тема роботи з двійковими файлами досить складна, її вивчення потрібен окремий урок. Тут будуть відзначені лише особливості функцій читання-запису до файлу, який сприймається як потік байтів.

Функції fread() і fwrite() приймають як параметри:

  1. адресу області пам'яті, куди дані записуються або звідки зчитуються,
  2. розмір одного даного будь-якого типу,
  3. кількість даних, що зчитуються зазначеного розміру,
  4. файловий покажчик.

Ці функції повертають кількість успішно прочитаних чи записаних даних. Тобто. можна замовити зчитування 50 елементів даних, а отримати тільки 10. Помилки при цьому не виникне.

Приклад використання функцій fread() та fwrite() :

#include #include main () (FILE * file; char shelf1 [50], shelf2 [100]; int n, m; file = fopen ("shelf1.txt", "rb"); n = fread (shelf1, sizeof (char) 50 , файл) ; fclose (file) ; file = fopen ( "shelf2.txt" , "rb" ) ; = " \0 " ; shelf2 [m] = " \n "; shelf2 [m + 1] = " \0 " ; file = fopen ("shop.txt", "wb"); fwrite (strcat (shelf2, shelf1), sizeof (char), n + m, file); fclose (file); )

Тут здійснюється спроба читання з першого файлу 50 символів. У n зберігається кількість реально зчитаних символів. Значення n може дорівнювати 50 або менше. Дані розміщуються в рядок. Те саме відбувається з другим файлом. Далі перший рядок приєднується до другого і дані скидаються в третій файл.

Вирішення задач

  1. Напишіть програму, яка запитує у користувача ім'я (адресу) текстового файлу, далі відкриває його і рахує в ньому кількість символів та рядків.
  2. Напишіть програму, яка записує файл дані, отримані з іншого файлу і так чи інакше змінені перед записом. Кожен рядок даних, отриманий із файлу, повинен поміщатися в структуру.