C запис та читання файлу. Введення даних із файлу та виведення у файл

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

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

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

Файлова системаназивається функціональна частина операційної системи, що забезпечує виконання операцій над файлами. Прикладами файлових систем є 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(потік, "ФорматВведення", аргументи);

Текстові файли

Розглянемо роботу з текстовим файлом Сі на прикладі. Створіть на диску текстовий файл з ім'ям TextFile.txt. Наберіть у цьому файлі такі рядки:

String_1 123 String_11, 456
String_2
String_3

Збережіть файл.

А це код програми на C, яка відкриває наш файл та зчитує з нього рядки:

/* *Author: @author Subbotin B.P..h> #include #define LEN 50 int main(void) ( puts("Text file operations"); char cArray; FILE *pTextFile = fopen("C:\\TextFile.txt", "r"); if(pTextFile == NULL) ( puts("Problems"); return EXIT_FAILURE; ) while(fgets(cArray, LEN, pTextFile) != NULL) ( printf("%s", cArray); ) fclose(pTextFile); return EXIT_SUCCESS; )

Щоб відкрити текстовий файл у C використовуємо функцію fopen:

FILE *pTextFile = fopen("C:\TextFile.txt", "r");

перший аргумент функції fopen вказує на файл, а другий каже, що файл відкритий для його читання.

Рядки зчитуємо за допомогою функції fgets:

fgets(cArray, LEN, pTextFile);

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

Після завершення роботи з файлом, його потрібно закрити:

fclose(pTextFile);

Отримуємо:

Російські літери у рядках теж проходять.

До речі, цю програму я зробив у Eclipse. Як працювати з C/C++ в Eclipse можна переглянути .

Отже, ми відкрили та рахували дані з текстового файлу.

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

/* Author: @author Subbotin B.P..h> #include int main(void) ( FILE *pTextFile = fopen("C:\\TextFileW.txt", "w"); char *cString = "This is a string"; char cNewLine = "\n"; int nVal = 123 ; if(pTextFile == NULL) ( puts("Problems"); return EXIT_FAILURE; ) fprintf(pTextFile, "%s%c", cString, cNewLine); fprintf(pTextFile, "%d", nVal); ;)

Створюємо текстовий файл для запису даних:

FILE *pTextFile = fopen("C:\TextFileW.txt", "w");

якщо файл вже є, то він буде відкритий, і всі дані будуть видалені.

C-рядок cString і число nVal записуються програмою в текстовий файл. cNewLine – це просто перехід на новий рядок.

Записуємо дані до текстового файлу за допомогою функції fprintf:

fprintf(pTextFile, "%s%c", cString, cNewLine);

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

До цього під час введення-виведення даних ми працювали зі стандартними потоками - клавіатурою та монітором. Тепер розглянемо, як у мові 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. Напишіть програму, яка записує файл дані, отримані з іншого файлу і так чи інакше змінені перед записом. Кожен рядок даних, отриманий із файлу, повинен поміщатися в структуру.

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

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

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

FILE *fopen(name, type);

name – ім'я файлу, що відкривається (включаючи шлях),
type - покажчик на рядок символів, що визначають спосіб доступу до файлу:

· "r" - відкрити файл для читання (файл має існувати);

· "w" - відкрити порожній файл для запису; якщо файл існує, його вміст втрачається;

· "a" - відкрити файл для запису в кінець (для додавання); файл створюється, якщо він не існує;

· "r+" - відкрити файл для читання та запису (файл повинен існувати);

· "w+" - відкрити порожній файл для читання та запису; якщо файл існує, його вміст втрачається;

· "a+" - відкрити файл для читання та доповнення, якщо файл не існує, то він створюється.

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

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

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

#include
int main()

char name="my.txt";

if(fp = fopen(name, "r")! = NULL)

// Відкрити файлу далося?
... // необхідні дії над даними

else printf("Не вдалося відкрити файл");

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

char fgetc (потік);

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

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

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

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

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

Функції fgets() і fputs() призначені для введення-виведення рядків, є аналогами функцій gets() і puts() до роботи з файлами.

fgets(Покажчик на Рядок, Кількість Символів, потік);

Символи читаються з потоку доти, доки не буде прочитано символ нового рядка "\n", який включається до рядка, або доки не настане кінець потоку EOF або не буде прочитано максимальне символів. Результат міститься в покажчик на рядок і закінчується нуль-символом "\0". Функція повертає адресу рядка.

fputs(Покажчик на Рядок, потік);

Копіює рядок у потік із поточної позиції. Завершальний нуль-символ не копіюється.
приклад Ввести число та зберегти його у файлі s1.txt. Вважати число з файлу s1.txt, збільшити його на 3 і зберегти у файлі s2.txt.

У цьому розділі буде розглянуто два способи роботи з фійлами та стандартний клас MFC CFileDialog.


1. Робота з файлами в C (працює і в C ++).


    #include
    #include

Void main(void)
{
FILE *file;
char* file_name = "file.txt";
char load_string = "none";

File = fopen (file_name, "w");

Fputs("string", file);

File = fopen (file_name, "r");
if(file! = 0)
{
fgets(load_string, 50, file);
cout)
else
{
cout)
fclose(file);
) Опис функцій роботи з файлами знаходяться у бібліотеці stdio.h
Спочатку треба створити покажчик на змінну типу FILE ( FILE* file;).
Відкриття файлу здійснюється викликом функції fopen ( file = fopen (file_name, "w");)
Перший параметр цієї функції - ім'я файлу, другий - вказує у якому режимі має бути відкритий файл. "w"- Відкрити для запису, "r"- відкрити для читання, "a"- Доповнення файлу (це найбільш використовувані режими, хоча є й інші). Запис та зчитування даних із файлу здійснюється такими функціями: fputc, fputs, fgetc, fgets, fprintf, fscanf(опис цих функцій дивіться в stdio.h).
Закриття файлу здійснюється викликом функції fclose ( fclose(file);).

Робота з файлами за допомогою MFC (класи CFile, CStdioFile, ...) та стандартний клас MFC CFileDialog.


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

CFile.

Клас CF ile

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

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

Open.

Відкриття та створення файлів

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

Virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError=NULL);

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

Другий параметр nOpenFlags визначає дію, що виконується методом Open із файлом, а також атрибути файлу. Нижче наведено деякі можливі значення параметра nOpenFlags:

  • CFile::modeCreate - Створюється новий файл. Якщо вказаний файл існує, його вміст стирається і довжина файлу встановлюється рівної нулю.
  • CFile::modeNoTruncate - Цей файл призначений для використання разом із файлом CFile::modeCreate. Якщо створюється вже існуючий файл, його вміст не буде видалено.

  • CFile::modeRea d - Файл відкривається лише для читання.
  • CFile::modeReadWrite - Файл відкривається для запису та читання.
  • CFile::modeWrite - Файл відкривається лише для запису.
  • CFile::typeText - Використовується класами, породженими від класу CFile, наприклад, CStdioFile, для роботи з файлами в текстовому режимі. Текстовий режим забезпечує перетворення комбінації символу повернення каретки та символу перекладу рядка.
  • CFile::Binary - Використовується класами, породженими від класу CFile, наприклад, CStdioFile, для роботи з файлами в двійковому режимі.
  • Необов'язковий параметр pError, який є вказівником на об'єкт класу CFileException, використовується лише у випадку, якщо виконання операції з файлом викликає помилку. При цьому об'єкт, що вказується pError, буде записана додаткова інформація.

    Метод Openповертає не нульове значення, якщо файл відкритий і нуль у разі помилки. Помилка при відкритті файлу може статися, наприклад, якщо методу Open вказаний для читання неіснуючий файл.

    Ідентифікатор відкритого файлу

    До складу класу CFile входить елемент даних m_hFile типу UINT. У ньому зберігається ідентифікатор відкритого файлу. Якщо об'єкт класу CFile вже створений, але файл ще не відкритий, то змінної m_hFile записана константа hFileNull.

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

    Закриття файлів

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

    Читання та запис файлів

    Для доступу до файлів призначено кілька методів класу CFile: Read, ReadHuge, Write, WriteHuge, Flush. Методи Read та ReadHugeпризначені для читання даних із попередньо відкритого файлу. У 32-розрядних операційних системах обидва методи можуть одночасно рахувати з файлу більше 65535 байт. Специфікація ReadHuge вважається застарілою та залишена лише для сумісності з 16-розрядними операційними системами.

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

    Для запису файл призначені методи Write і WriteHuge. У 32-розрядних операційних системах обидва методи можуть одночасно записувати у файл більше 65 535 байт. Методи записує у відкритий файл nCount байт із буфера lpBuf. У разі помилки запису, наприклад переповнення диска, методи викликає обробку виключення.

    Метод Flush

    Коли використовується метод Write або WriteHuge для запису даних на диск, вони можуть бути певний час у тимчасовому буфері. Щоб переконатися, що необхідні зміни внесені у файл диску, потрібно скористатися методом Flush.

    Операції з файлами

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

    Для зміни імені файлу клас CFile включає статичний метод Renameвиконує функції цієї команди. Метод не можна використовувати для перейменування каталогів. У разі помилки метод викликає виняток.

    Для видалення файлів у класі CFile включений статичний метод Remove, що дозволяє видалити вказаний файл. Цей метод не дозволяє видаляти каталоги. Якщо видалити файл неможливо, метод викликає виняток.

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

    Віртуальна версія методу GetStatusвизначає стан відкритого файлу, пов'язаного з об'єктом класу CFile. Цей метод викликається лише тоді, коли об'єкт класу CFile створено та файл відкритий.

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

    Блокування

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

    Встановити блокування можна за допомогою методу LockRange. Щоб зняти встановлені блокування, треба скористатися методомUnlockRange. Якщо в одному файлі встановлено кілька блокувань, то кожне з них має зніматись окремим викликом методуUnlockRange.

    Позиціювання

    Щоб перемістити вказівник поточної позиції файлу в нове положення, можна скористатися одним із таких методів класу CFile - Seek, SeekToBegin, SeekToEnd.До складу класу CFileтакож входять методи, що дозволяють встановити та змінити довжину файлу, -GetLength, SetLength.

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

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

    Seek. Він дозволяє перемістити покажчик на кілька байт щодо початку, кінця чи поточної позиції покажчика.

    Щоб перемістити вказівник на початок або кінець файлу, найбільш зручно використовувати спеціальні методи. Метод

    SeekToBeginпереміщує покажчик на початок файлу, а методSeekToEnd- У його кінець.

    Але визначення довжини відкритого файлу зовсім необов'язково переміщати його покажчик. Можна скористатися методом

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

    Поточну позицію вказівника файлу можна визначити за допомогою методу

    GetPosition. Повертається методомGetPosition32-розрядне значення визначає зміщення покажчика з початку файла.

    Характеристики відкритого файлу

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

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

    Наступний метод класу CFile дозволяє встановити шлях файлу. Цей метод не створює, не копіює та не змінює імені файлу, він лише заповнює відповідний елемент даних в об'єкті класу CFile.

    Клас C

    MemFile

    До бібліотеки MFC входить клас

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

    Працюючи з об'єктами класу

    CMemFile, можна використовувати практично всі методи класуCFile, що були описані вище. Можна записувати дані до такого файлу або зчитувати їх. Крім цих методів до складу класуCMemFileвключено додаткові методи.

    Для створення об'єктів класу CMemFile призначено два різні конструктори. Перший конструктор CMemFile має лише один необов'язковий параметр nGrowBytes:

    CMemFile(UINT nGrowBytes=1024);

    Цей конструктор створює в пам'яті порожній файл. Після створення файл автоматично відкривається (не потрібно викликати метод Ope

    n).

    Коли починається запис у такий файл, автоматично виділяється блок пам'яті. Для отримання пам'яті методи класу

    CMemFileвикликають стандартні функціїmalloc, reallocі free. Якщо виділеного блоку пам'яті недостатньо, його розмір збільшується. Збільшення блоку пам'яті файлу відбувається частинами nGrowBytes байт. Після видалення об'єкта класуCMemFileпам'ять, що використовується автоматично повертається системі.

    Другий конструктор класу CMemFile має складніший прототип. Це конструктор використовується у тих випадках, коли програміст сам виділяє пам'ять для файлу:

    CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes=0);

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

    Необов'язковий параметр nGrowBytes використовується комплексніше, ніж у першому конструкторі класу. Якщо nGrowBytes містить нуль, створений файл буде містити дані з буфера lpBuffer. Довжина такого файлу дорівнюватиме nBufferSize.

    Якщо nGrowBytes більше за нуль, то вміст буфера lpBuffer ігнорується. Крім того, якщо в такий файл записується більше даних, ніж міститься у відведеному буфері, його розмір автоматично збільшується. Збільшення блоку пам'яті файлу відбувається частинами nGrowBytes байт.

    CMemFileдозволяє отримати вказівник на область пам'яті, що використовується файлом. Через цей покажчик можна безпосередньо працювати із вмістом файлу, не обмежуючи себе методами класуCFile. Для отримання вказівника на буфер файлу можна скористатися методом Detach. Перед цим корисно визначити довжину файлу (і відповідно розмір буфера пам'яті), викликавши методGetLength. Detachзакриває даний файл і повертає покажчик на блок пам'яті, що використовується. Якщо знову потрібно відкрити файл і зв'язати з ним оперативний блок пам'яті, потрібно викликати методAttach.

    Слід зазначити, що з управління буфером файлу клас

    CMemFileвикликає стандартні функціїmalloc, reallocі free. Тому, щоб не порушувати механізм управління пам'яттю, буфер lpBuffer має бути створений функціямиmallocабо calloc.

    Клас CStdioFile

    Тим, хто звик користуватися функціями потокового введення/виводу зі стандартної бібліотеки C та C++, слід звернути увагу на клас

    CStdioFile, успадкований від базового класуCFile. Цей клас дозволяє виконувати буферизоване введення/виведення в текстовому та двійковому режимі. Для об'єктів класуCStdioFileможна викликати майже всі методи класу CFile.CStdioFileвходить елемент даних m_pStream, що містить покажчик на відкритий файл. Якщо об'єкт класуCStdioFileстворено, але файл ще відкритий, або закритий, то m_pStream містить константу NULL.CStdioFileмає три різні конструктори. Перший конструктор класу CStdioFile не має параметрів. Цей конструктор лише створює об'єкт класу, але не відкриває жодних файлів. Щоб відкрити файл, потрібно викликати методOpenбазового класуCFile.

    Другий конструктор класу

    CStdioFileможна викликати, якщо файл вже відкритий і потрібно створити новий об'єкт класу CStdioFile та зв'язати з ним відкритий файл. Цей конструктор можна використовувати, якщо файл був відкритий стандартною функцієюfopen. Параметр методу повинен містити вказівник на файл, отриманий викликом стандартної функціїfopen.

    Третій конструктор можна використати, якщо треба створити об'єкт класу

    CStdioFileвідкрити новий файл і зв'язати його з щойно створеним об'єктом.

    Для читання та запису в текстовий файл клас CStdioFile включає два нові методи:

    ReadStringі WriteString. Перший метод дозволяє прочитати з файлу рядок символів, а другий метод – записати.

    Приклади запису та читання з файлу

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

    Відкриття файлу та читання з нього

    CString m_Text; …… // Створення стандартної панелі вибору файлу Open CFileDialog DlgOpen(TRUE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY,(LPCSTR)" Text Files (*.txt) |*.txt||"); // Відображення стандартної панелі вибору файлу Open if(DlgOpen.DoModal()==IDOK) ( // створення об'єкта та відкриття файлу для читання CStdioFile File(DlgOpen.GetPathName(),CFile::modeRead|CFile::typeBinary); // Читання з файлу рядка CString& ref=m_Text; File.ReadString(ref ); // Передається посилання на рядок m_Text)

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

    CString m_Text; …… // Створення стандартної панелі вибору файлу SaveAs CFileDialog DlgSaveAs(FALSE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, (LPCSTR)" Text Files (*.txt) |*.txt||"); // Відображення стандартної панелі вибору файлу SaveAs if(DlgSaveAs.DoModal()==IDOK) ( // створення об'єкта та відкриття файлу для запису CStdioFile File(DlgSaveAs.GetPathName(), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary); // запис у файл рядка File.WriteString((LPCTSTR)m_Text); )
      знаходиться робочий код програми, виконаної для простоти як консольного докладання під MFC. Щоб програма працювала не забудьте зробити таке:

      Запустіть програму - Build / Rebuild all (будуть помилки), виберіть Build / Set active configuration - Win 32 Realise, виберіть пункт меню "Project", далі "Settings...", закладку "C/C++", Category - Code Generation та у пункті "Use run-time library" виберіть "Multithreaded". Після цього зробіть знову Build/Rebuild all і програма буде працювати.