Файлове введення
Матеріал з Вікіпедії – вільної енциклопедії
Мова програмування Сі підтримує безліч функцій стандартних бібліотек для файлового введення та виведення. Ці функції становлять основу файлу заголовка стандартної бібліотеки мови Сі.
Функціональність введення-виведення мови Сі за поточними стандартами реалізується на низькому рівні. Мова Сі абстрагує всі файлові операції, перетворюючи їх у операції з потоками байтів, які можуть бути як потоками введення, так і потоками виведення. На відміну від деяких ранніх мов програмування, мова Сі не має прямої підтримки довільного доступу до файлів даних; щоб вважати записану інформацію всередині файлу, програмісту доводиться створювати потік, що шукає всередині файлу, а потім послідовно зчитувати байти з потоку.
Потокова модель файлового вводу-виводу була багато в чому популяризована завдяки операційній системі Unix, написаній мовою Сі. Велика функціональність сучасних операційних систем успадкувала потоки від Unix, а багато мов сімейства мов програмування Сі успадкували інтерфейс файлового введення-виведення мови Сі з невеликими відмінностями (наприклад, PHP). Стандартна бібліотека C++ відображає потокову концепцію у своєму синтаксисі (дивіся stream).
| Зміст [показати] |
[ред.]Відкриття файлу за допомогою fopen
Файл відкривається за допомогоюfopen, яка повертає інформацію потоку введення-виводу, прикріпленого до вказаного файлу або іншого пристрою, з якого йде читання (або який записується). У разі невдачі функція повертає нульовий покажчик.
Подібна функціяfreopen бібліотеки Сі виконує аналогічну операцію після першого закриття будь-якоговідкритого потоку, що з її параметрами.
Вони визначаються як
FILE *fopen(const char *path, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *fp);
Функція fopen по суті є «обгорткою» вищого рівня системного виклику open операційної системи Unix. Аналогічно, fclose є обгорткою системного виклику Unix close, а сама структура FILE мови Сі найчастіше звертається до відповідного файлового дескриптора Unix. У оточенні POSIX функціяfdopen може використовуватися для ініціалізації структури FILE файловим дескриптором. Тим не менш, файлові дескриптори як виключно Unix-концепція не представлені у стандарті мови Сі.
Параметр mode (режим) для fopen і freopen має бути рядковий і починатися з однієї з наступних послідовностей:
| режим | опис | починає с.. | ||
| r | rb | відкриває для читання | початку | |
| w | wb | відкриває для запису (створює файл у разі його відсутності). Видаляє вміст та перезаписує файл. | початку | |
| a | ab | відкриває для додавання (створює файл у разі його відсутності) | кінця | |
| r+ | rb+ | r+b | відкриває для читання та запису | початку |
| w+ | wb+ | w+b | відкриває для читання та запису. Видаляє вміст та перезаписує файл. | початку |
| a+ | ab+ | a+b | відкриває для читання та запису (додає у разі існування файлу) | кінця |
Значення "b" зарезервовано для двійкового режиму С. Стандарт мови Сі описує два види файлів - текстові та двійкові - хоча операційна системане вимагає їх розрізняти (проте, для деяких компіляторів, наприклад LCC, вказівка 'b' під час роботи з бінарним файлом принципово важлива!).Текстовий файл— файл, що містить текст, розбитий на рядки за допомогою деякого символу, що розділяє закінчення рядка або послідовності (у Unix — одиночний символ перекладу рядка; у Microsoft Windows за символом перекладу рядка слід знак повернення каретки). При зчитуванні байтів з текстового файлу символи кінця рядка зазвичай зв'язуються (замінюються) з перекладом рядка для спрощення обробки. При записі текстового файлу одиночний символ перекладу рядка перед записом зв'язується (замінюється) із специфічною для ОС послідовністю символів кінця рядка.Двійковий файл— файл, з якого байти зчитуються і виводяться в «сирому» вигляді без будь-якого зв'язування (підстановки).
При відкритому файлі в режимі оновлення ('+' як другий або третій символ аргументу позначення режиму) і введення і виведення можуть виконуватися в одному потоці. Тим не менш, запис не може йти за читанням без проміжного виклику fflush або функції позиціонування у файлі (fseek, fsetpos або rewind), а читання не може слідувати за записом без проміжного виклику функції позиціонування у файлі. [1]
Режими запису та додавання намагаються створити файл із заданим ім'ям, якщо такого файлу ще не існує. Як зазначалося вище, якщо ця операція закінчується невдачею, fopen повертає NULL.
[ред.]Закриття потоку за допомогою fclose
Функція fclose приймає один аргумент: покажчик на структуру потоку FILE для закриття.
int fclose(FILE * fp);
Функція повертає нуль у разі успіху та EOF у разі невдачі. При нормальному завершенні програми функція викликається автоматичнокожного відкритого файлу.
[ред.]Читання з потоку
[ред.]за допомогою fgetc
Функціяfgetc застосовується для читання символу потоку.
int fgetc(FILE * fp);
У разі успіху, fgetc повертає наступний байт або символ з потоку (залежить від того, файл «двійковий» або «текстовий» (як вище обговорювалося). В іншому випадку, fgetc повертає EOF. вказівником на файл.)
Стандартний макросgetc також визначений у успішно працюючи як fgetc, крім одного: будучи макросом, він може обробляти свої аргументи більше одного разу.
Стандартна функціяgetchar також визначена в , вона не приймає аргументів і еквівалентна getc(stdin).
[ред.]«Пастка» EOF
Поширеною помилкою є використання fgetc, getc або getchar для присвоєння результату змінної типу charпередпорівнянням його з EOF. Наступний фрагмент коду демонструє цю помилку, а поряд наведено коректний варіант:
| Помилка | Правильно |
| char c;while ((c = getchar()) != EOF) | int c;while ((c = getchar()) != EOF) |
Потрібно враховувати систему, у якій тип char, довжина якого становить 8 біт (зокрема, архітектура x86), становить 256 різних значень. getchar може повертати будь-який із 256 можливих символів, а також може повертати EOF для позначення кінця файлу, значення якого не може збігатися з жодним із значень char.
Коли результат getchar присвоюється змінній типу char, яка може уявити лише 256 різних значень, відбувається вимушена втрата інформації — при стисканні 257 значень у 256 «місць» відбувається колізія.Значення EOF при конвертації в char стає невідмінним від будь-якого з решти 256 символів. Якщо цей символ виявлений у файлі, код, наведений вище, може прийняти його за ознаку кінця файлу, або, що ще гірше, якщо тип char беззнаковий, тоді з урахуванням того, що EOF значення негативне, воно ніколи не зможе стати рівним будь-якому беззнаковому char, і таким чином, приклад вище не закінчиться на мітці кінця файлу, а буде виконуватися вічно, повторно друкуючи символ, що виходить при конвертації EOF в char.
У системах, де int і char однакового розміру [яких?] [джерело не вказано 512 днів] , навіть «правильний» варіант працюватиме некоректно через подібність EOF та іншого символу. Правильним варіантом обробки подібної ситуації є перевірка feof і ferror після того, як getchar поверне EOF. Якщо feof визначить, що кінець файлу ще досягнуто, а ferror «повідомить», що помилок немає, то EOF, повернутий getchar може вважатися поточним символом. Такі додаткові перевірки робляться рідко, оскільки більшість програмістів вважає, що їхній код ніколи не буде виконуватися на подібних системах з «великим char». Інший спосіб полягає у використанні перевірки при компіляції, що UINT_MAX > UCHAR_MAX, яка хоча запобігатиме компіляції на подібних системах.
[ред.]за допомогою fgets
Функціяfgets застосовується для читання рядка потоку. Зчитування відбувається до тих пір, поки не буде досягнуто кінця рядка (hex:0D0A, еквівалентні в лістингах\n ) або довжина рядка, в яку відбувається зчитування. Припустимо, ми маємо файлsome_file.txt з текстом
паліндроми А в Єнісеї – синьова. А лама мала. А лисиця, він розумний - пацюк сир до нього носив. (І. Бабицький) #include #include int main (intargc, char* argv[])/* argc зберігає кількість параметрів, а argv[] покажчики ці параметри. Наприклад, якщо ми запустимо виконуваний файл "fgets_example param1 param2", то argc дорівнюватиме 3, а argv[] = */< FILE *file; char *fname = "some_file.txt"; char result_sting[20];//Рядок у 20 символівfile = fopen(fname, "r"); if(file == 0) < printf("не можу відкрити файл '%s'",fname); return 0; >int i=0; char *real_tail; while(fgets(result_sting,sizeof(result_sting),file)) < real_tail=""; printf("Рядок %d:Довжина рядка - %d:",i++,strlen(result_sting)); if(result_sting[strlen(result_sting)-1] == '\n ')//перевіряємо чи є останній елемент у рядку символом її закінчення< real_tail="\ n"; result_sting[strlen(result_sting)-1]='\0 '; >;// ця частина коду додана лише для відображення символу кінця рядка в консоль без перекладу на новий рядокprintf("%s%s\n ",result_sting,real_tail); > fclose(file); return 0;>
в результаті виконання ми отримаємо
Рядок 0:Довжина рядка - 11:паліндроми\nРядок 1:Довжина рядка - 19: А в Єнісеї - сіРядок 2:Довжина рядка - 6:нева.\nРядок 3:Довжина рядка - 17: А лама мала.\nРядок 4:Довжина рядки - 19: А лисиця, він розумнийРядок 5:Довжина рядка - 19:- щур сир до ньогоРядок 6:Довжина рядка - 19:носила. (І. БабицькийРядок 7:Довжина рядка - 2:й)
Функціяstrlen визначає довжину рядка за кількістю символів до '\0' наприклад
printf("%d",strlen("123\0 123"));//виведе 4
[ред.]fwrite
У мові програмування Си функціїfread іfwrite відповідно реалізують файлові операції введення та виведення. fread та fwrite оголошені в .
[ред.]Запис у файл за допомогою fwrite
fwrite визначається як
int fwrite (const char * array, size_t size, size_t count, FILE * stream);
Функція fwrite записує блок даних потік. Таким чином, запишеться масив елементів array в поточну позицію в потоці. Для кожного елемента запишеться size байт. Індикатор позиції в потоці зміниться на кількість байт, записаних успішно. Повертається значення дорівнює count у разі успішного завершення запису. У разі помилки значення, що повертається, буде менше count.
Наступна програма відкриває файл приклад.txt, записує рядок символів, а потім його закриває.
#include #include #include int main(vo); return 0;>
[ред.]Запис у потік за допомогою fputc
Функціяfputc застосовується для запису символу потоку.
int fputc(int c, FILE * fp);
Параметр c "тихо" конвертується в unsigned char перед виведенням. Якщо пройшло успішно, fputc повертає записаний символ. Якщо помилка, то fputcповертає EOF.
Стандартний макросputc також визначено в , працюючи в загальному випадку аналогічно fputc, за винятком того моменту, що будучи макросом, він може обробляти свої аргументи більше одного разу.
Стандартна функціяputchar, також визначена в , приймає тільки перший аргумент, і є еквівалентною putc(c, stdout), деcє згаданим аргументом.
[ред.]Приклад використання
Нижченаведена програма на мові Сі відкриває двійковий файл з назвоюмойфайл, читає п'ять байт з нього, а потім закриває файл.
#include #include int main(vo, stderr); return EXIT_SUCCESS;>
Двійковий (бінарний) файл — у сенсі: послідовність довільних байтів. Назва пов'язана з тим,що байти складаються з біт, тобто двійкових (англ. ) цифр.
У вузькому значенні слова двійкові файли протиставляються текстовим файлам. При цьому з точки зору технічної реалізації на рівні апаратури текстові файли є окремим випадком двійкових файлів, і, таким чином, у широкому значенні слова під визначення «двійковий файл» підходить будь-який файл.
Часто двійковими файлами називають файли, що виконуються, і стислі дані, проте некоректно так обмежувати це поняття.
Лістинг 5.6. Програма підрахунку числа символів '\r' у файлі.
#include int main(void) < FILE* fp = fopen("my_file.txt","w"); if(fp != NULL) < fprintf(fp,"It is\nan example using\nan binary file."); > fclose(fp); char ch; int cnt = 0; fp = fopen("my_file.txt","r"); if(fp != NULL) < while((ch = getc(fp)) != EOF) if(ch == 'r') cnt++; > fclose(fp); printf("Text file: cnt = %d\n", cnt); cnt=0; fp = fopen("my_file.txt","rb"); if(fp != NULL) < while((ch = getc(fp)) != EOF) if(ch == 'r') cnt++; > fclose(fp); printf("Binary file: cnt = %d\n",cnt); return 0; >
Лістинг 5.7. Використання функцій fwrite() та fread().
#include void main( void ) < FILE *stream; char list[30]; int i, numread, numwritten; if( (stream = fopen( "fread.out", "wb")) != NULL ) < for (i = 0; i