Под файлом понимается область на диске, в которой хранится какая-то информация, например, текст программы, данные для программы, документы.
Файлы могут быть текстовые и двоичные. Примером двоичных файлов является EXE-файл, содержащий готовую к выполнению программу. Двоичные файлы рассматривать не будем.
Текстовые файлы состоят обычно из строки символов, причем каждая строка заканчивается символом перевод строки(новая строка), а не нуль символом, как строки в Си –программах. Такая форма хранения информации удобна для человека. При просмотре или редактировании файла с помощью текстового редактора символы перевода строки не видны.
Информация в текстовом файле может храниться и в виде последовательности так называемых записей фиксированной длины без всяких разделителей. Так можно хранить различные таблицы, состоящие из нескольких различных полей.
При работе с файлами в программе на Си необходимо вначале открыть файлы с помощью функции fopen().
При этом для каждого файла создается структура, содержащая информацию о файле (имя файла, вид обработки, адрес буфера ввода/вывода и др.) Шаблон такой структуры описан в библиотечном файле stdio.h. Краткое название этого шаблона –FILE. В программе необходимо для каждого файла описать указатель на структуру типа FILE и присвоить значения этим указателям с помощью функции - fopen().
Для чтения информации из файла используются функции:
fscanf() – форматированный ввод;
fgetc() – ввод одного символа;
fgets() – ввод строки;
fread() – ввод определенного числа байт(символов).
Для записи информации в файл служат следующие функции:
fprintf() – форматированный вывод;
fputc() – вывод одного символа;
fputs() – вывод строки;
fwrite() - – вывод определенного числа байт(символов)
Обычно к файлу применяется последовательный доступ: чтение из файла происходит последовательно либо байт за байтом, либо построчно, либо блоками байтов, аналогично происходит запись в файл. Однако возможен и прямой (произвольный ) доступ к файлу. Он используется, когда файл состоит из записей одинаковой (фиксированной) длины. Для произвольного доступа к файлу служит функция fseek(). Она устанавливает указатель текущей позиции в файле в указанное место.
После завершения работы с файлом его нужно закрыть с помощью функции fclose().
Пример. Дан файл, содержащий телефонный справочник. Структура записи: номер телефона, фамилия и инициала абонента, адрес. Каждая запись заканчивается символом перевод строки. Записи в файле не упорядочены по алфавиту. Напечатать список телефонов абонентов на указанную букву (без адресов).
а) пример строки (записи) в файле:
35-87-82 Нигматуллин Р.Р. Даурская 15-13"ПС"
9 симв. 20 симв. <=25 симв. 1 симв.
Программа
#include <stdio.h>
/*шаблон структуры записи*/
struct abonent
{char nom[9]; /*номер телефона*/
char fio[20]; /*фамилия и.о.*/
char adres[27]; /*адрес +'\n'+'\0'*/
};
int main()
{ struct abonent tz; /*тек. запись файла*/
FILE fvh; /ссылка на вх . файл*/
char bukva; /*заданная буква*/
fvh=fopen("phone.txt", "r");
if (fvh==NULL) {printf("файл phone.txt в тек. каталоге не найден\n");
return(1); /*выход*/}
puts("Введите букву"); bukva=getchar();
puts("\nСписок абонентов");
while (fgets(&tz, 56, fvh)!=NULL) /*пока не конец файла*/
Дан файл, содержащий сведения о пациентах клиники. Структура файла: фамилии и инициалы пациента, год рождения, диагноз. Напечатать список пациентов старше заданного возраста с заданным диагнозом.
а) записи переменной длины
фио гр диагноз"ПС"
20сим. 4симв.<=50 1симв.
симв.
#include <stdio.h>
#include<string.h>
/*шаблон структуры записи*/
struct patient
{char fio[20]; /* фамилия и.о */
char gr[4]; /*год рождения.*/
char diag[52]; /* диагноз +'\n+'\0' */
}
int vozr(char gr[]);
int main()
{ struct patient tz; /*тек. запись файла*/
FILE fvh; /ссылка на вх . файл*/
char zd[51]; /*заданный диагноз*/
int zv; /*заданный возраст*/
int n=0; /*порядковый номер пациента в списке*/
int dl; /*длина строки*/
if ((fvh=fopen("diagpac.txt", "r"))==NULL)
{puts("Файл в тек. каталоге не найден\n");
return(1); /*выход*/}
puts("Укажите диагноз"); gets (diag);
puts("Укажите возраст"); scanf("%d", &zv);
printf ("\nСписок пациентов старше %dлет с заданным диагнозом\n",zv);
dl=strlen(zd); /*определение кол-ва символов в заданном диагнозе*/
while(fgets(&tz,76,fvh)!=NULL)
{ if (strncmp(zd, tz.diag, dl)==0) /*диагнозы совпадают*/
if (vozr(tz.gr)>zv) /*возраст пациента больше заданного*/
{tz.fio[19]='\0';
printf ("%d %s\n", ++n, tz.fio);}
}
fclose(fvh); return(0); }
/*функция определения возраста пациента*/
int vozr( char gr[4])
/*Вход gr -год рождения*/
{ char str [5]; /*доп. массив для преобразования gr в строку*/
while (fread (&tz, sizeof(struct patient), 1, fvh)!=0)
{ ….. 74
Лекция 4.
Некоторые функции доступа к файлам
1) fopen – открытие файла
Прототип функции
FILE *fopen(char *filename, char *type);
1-ый аргумент задает имя файла, 2-ой – вид обработки, он может принимать следующие значения:
"r" – чтение файла;
"w" – запись в файл;
"a" – добавление в конец файла;
"r+" -изменение файла (чтение и запись).
Если type="a", указатель текущей позиции в файле устанавливается в конец файла, в остальных случаях – на начало файла.
Функция fopen() возвращает указатель на структуру типа FILE, описывающую файл. При попытке открыть несуществующий файл для чтения или изменения, функция возвращает значение NULL.
Примеры обращения к fopen():
FILE* fout, *fmod; char fname [13];
fout = fopen ("file1", "w");
gets (fname); fmod= fopen (fname, "r+");
2) fclose – закрытие файла.
Функция имеет один аргумент – указатель на файл.
Примеры:
fclose(fout); fclose (fmod);
3) fgets - чтение одной строки файла
Прототип функции:
char *fgets(char *s, int n, FILE *f);
Функция считывает символы из файла, на который ссылается указатель f, в строку с указателем s. Второй аргумент n задает предельную длину считываемой строки. Функция прекращает работу после считывания символа перевода строки или после считывания символов общим числом (n-1) ( в зависимости от того, что произойдет раньше). В любом случае нуль-символ ('\0') добавляется в конец строки. В отличие от функции gets() символ перевода строки сохраняется.
Функция возвращает NULL, если встречается символ конца файла. Пример:
FILE *in;
char str[80];
….
fgets(str, 80,in);
4) fputs - запись строки в файл.
Прототип:
int fputs (char *s, FILE *f);
указатель на строку указатель на файл
Строка записывается в файл без завершающего ‘\0’.
Пример обращения:
FILE *out;
struct
{char a[10];
char b[20];
char c[15];
} string;
...
fputs (&string, out);
5) fread - чтение из файла одной или нескольких записей заданной длины.
int fread(void *ptr, int size, int number, FILE *f);
size - длина одной записи в байтах;
number - количество записей;
f - ссылка на входной файл;
ptr - указатель на область памяти, куда следует поместить считанные из файла записи.
Функция возвращает число фактически считанных записей. При обнаружении конца файла возвращается 0.
6) fwrite - вывод в файл одной или нескольких записей заданной длины.
int fwrite (void *ptr, int size, int number, FILE *f);
Функция выводит из области, на которую указывает ptr, в файл с указателем f, number записей длины size каждая.
Функция возвращает количество фактически записанных записей.
Пример обращения:
FILE *out;
struct s1
{...
} zap;
void *ptr_zap = &zap;
...
fwrite (ptr_zap, sizeof(struct s1), 1, out);
7) fscanf - форматированный ввод из файла.
fscanf отличается от scanf только тем, что имеет дополнительный аргумент - указатель файла.
Пример обращения:
FILE *in; int k; char slovo[15];
...
fscanf(in, “%d %d %s”,&k, slovo);
8) fprintf - форматированный вывод в файл. 1-ый аргумент - указатель на файл, остальные, как у printf.
9) fseek - изменение текущей позиции в файле.
int fseek(FILE *f, long offset, int code);
f - ссылка на файл:
offset - смещение текущей позиции в файле:
code - код, определяющий относительно какой точки в файле задается смещение.
сode может принимать целые значения:
0 - начало файла, 1 - текущая позиция, 2 - конец файла.
Примеры:
FILE * fp; struct s1 {...} zap; long dl_zap;
dl_zap= sizeof(struct s1); fp=fopen(“ ”, “r+”);
fseek(fp, dl, 0); /* установить указатель текущей позиции на 2-ую запись в файле */
fread (&zap, dl, fp);
fseek(fp, -2*dl, 2); /* установить указатель тек. позиции на предпоследнюю запись в файле */
fwrite(&zap, dl, 1, fp);
10) ftell - возвращает смещение текущей позиции в файле относительно начала файла.
long ftell(FILE *f);
Пример:
long dlf; /* длина файла*/
fseek(fp, 0, 2); dlf=ftell(fp);
Пример. Дан файл, состоящий из записей фиксированной длины. Переписать записи в обратном порядке в другой файл. Имена файлов и длину записей передавать программе в виде параметров.
Командная строка:
имя.exe имя_вх_файла имя_вых_файла длина_записи
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
/* argc -количество параметров (д.б. 4) */
/* argv вектор указателей на параметры */
/* argv[0] ссылается на exe -файл */
/* argv[1] указатель на имя входного файла */
{ FILE *fvh, *fvih; /*ссылка на вх., вых. файлы */
long dlz; /*длина записи */
char *buf; /*указатель буфера ввода*/
long dlf; /*длина файла в байтах*/
int kolz; /*кол-во записей*/
int i; /*номер текущей записи*/
if (argc!=4) {printf(“Неверная командная строка\n”); return 1;}
fvh=fopen(argv[1], “r”);
if (fvh==NULL) {printf(“Нельзя открыть файл%s\n”, argv[1]); return 2;}
dlz=atol(argv[3]); /*преобразование в тип long*/
buf=malloc(dlz); /*выделение памяти для буфера ввода-вывода*/