Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
http.doc
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
1.34 Mб
Скачать

Fseek() и произвольный доступ

Можно выполнять операции произвольного чтения и записи, используя систему буферизированного ввода/вывода, с помощью fseek(), устанавливающей текущую файловую позицию. Она имеет следующий прототип:

int fseek(FILE *fp long нисло_байт, int начало);

где fp - это указатель на файл, возвращенный fopen(), число_байт - это длинное целое, содер­жащее число байт от начала до позиции маркера, а начало - это одно из следующих макроопре­делений (определенных в stdio.h):

Макроопределение

Смысл

SEEK_SET

SEEK_CUR

SEEK_END

Начало файла

Текущая позиция

Конец файла

Макроопределения определены как целочисленные значения, причем SEEK_SET соответствует 0, SEEK_CUR - 1, a SEEK_END - 2. Следовательно, для перехода на число_байт от начала файла следует установить начало в SEEK_SET. Для перехода от текущей позиции надо использо­вать SEEK_CUR, а для перехода от конца файла - SEEK_END. Функция fsee() возвращает 0 в случае удачи или ненулевое значение в случае ошибки. Например, можно использовать следующий код для чтения 234-го байта файла test: int func1(void) { FILE *fp; if((fp=fopen("test", "rb")) == NULL){ printf("Cannot open file."); exit(1); } fseek(fp, 234L, O); return getc(fp); /* чтение одного символа в 234-й позиции */ } }

Другим примером, использующим функцию fseek(), является следующая программа dump, по­зволяющая просмотреть содержимое, как в ASCII, так и в шестнадцатиричных форматах. Можно смотреть на файл 128-байтными «секторами», причем двигаться можно в произвольном направле­нии. Для выхода из программы следует набрать -1, когда будет предложено ввести номер сектора. Обратим внимание на использование fread() для чтения файла. Если остается прочитать меньше чем SIZE байт, то число, передаваемое в display(), как раз и определяет, сколько символов необхо­димо вывести. (Надо помнить, что fread() возвращает число прочитанных элементов.) Введем про­грамму в компьютер и основательно с ней разберемся: /* dump: простая дисковая утилита для просмотра, использующая fseek. */ #include <stdio.h> #include <ctype.h> #define SIZE 128 void display(int numread); char buf[SIZE]; void display(); int main(int argc, char *argv[]) { FILE *fp; int sector, numread; if(argc!=2) { printf("Usage: dump filename"); return 1; } if((fp=fopen(argv[1], "rb"))==NULL) { printf("Cannot open file."); return 1; } do { printf("Enter sector: "); scanf("%d", &sector); if(sector >= 0) { if(fseek(fp, sector*SIZE, SEEK_SET)) { printf("seek error"); } if((numread=fread(buf, 1, SIZE, fp)) != SIZE) printf("EOF reached."); display(numread); } } while(sector>=0); return 0; }

/* вывод содержимого файла */ void display(int numread) { int i, j; for(i=0; i<numread/16; i++) { for (j=0; j<16; j++) printf("%3X", buf[i*16+j]); printf(" "); for(j=0; j<16; j++) { if(isprint(buf[i*16+j])) printf("%c", buf[i*16+j]); else printf("."); } printf("\n"); } }

Надо обратить внимание, что библиотечная функция isprint() используется для определения вы­водимых символов. Функция isprint() возвращает истину, если символ можно вывести, и ложь - если нельзя. Для ее использования необходимо подключить заголовочный файл ctype.h. Пример работы dump можно увидеть на рис.

Рисунок: Пример работы дисковой утилиты просмотра

fprintf() и fscanf()

Помимо основных функций ввода/вывода, система буферизированного ввода/вывода содержит fprintf() и fscanf(). Данные функции ведут себя так же, как и printf() и scanf(), за тем исключением, что работают с дисковыми файлами. Они имеют следующие прототипы:

int fprintf(FILE *fp, const char *форматная_строка, ...);

int fscanf(FILE *fp, const char * форматная_строка, ...);

где fp - это указатель на файл, возвращаемый fopen(). Если не принимать во внимание, что они перенаправляют вывод в файл, то можно считать, что работа данных функций полностью иден­тична printf() и scanf() соответственно.

Для демонстрации использования данных функций следующая программа содержит в файле простой телефонный справочник. Можно ввести имена и номера или узнать, какой номер соот­ветствует определенному имени.

/* простой телефонный справочник */ #include <conio.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> void add_num(void), lookup(void); char menu(void); int main(void) { char choice; do { choice = menu(); switch(choice) { case 'a': add_num(); break; case '1': lookup(); break; } } while (choice!='q'); return 0; }

/* вывод меню и получение запроса */ char menu(void) { char ch; do { printf("(A)dd, (L)ookup, or (Q)uit: "); ch = tolower(getche()); printf("\n"); } while(ch != 'q' && ch != 'a' && ch != '1'); return ch; }

/* добавление имени и номера в справочник */ void add_num(void) { FILE *fp; char name[80]; int a_code, exchg, num;

/* открытие для присоединения */ if((fp=fopen("phone", "a")) == NULL) { printf("Cannot open directory file."); exit(1); } printf("Enter name and number: "); fscanf(stdin, "%s%d%d%d", name, &a_code, &exchg, &num); fscanf(stdin, "%*c"); /* удаление возврата каретки из потока ввода */

/* запись в файл */ fprintf(fp,"%s %d %d %d\n", name, a_code, exchg, num); fclose(fp); }

/* поиск числа по имени */ void lookup(void) { FILE *fp; char name[80], name2[80]; int a_code, exchg, num;

/* открытие для чтения */ if((fp=fopen ("phone","r")) == NULL) { printf("Cannot open directory file."); exit(1); } printf("name? "); gets(name);

/* поиск числа */ while(!feof(fp)) { fscanf(fp,"%s%d%d%d", name2, &a_code, &exchg, &num); if (!strcmp(name, name2)) { printf("%s: (%d) %d-%d\n",name, a_code, exchg, num); break; } } fclose(fp); }

Введем и запустим данную программу. После введения нескольких имен и чисел просмотрим файл phone. Как и следовало ожидать, он будет иметь вид как и обычная информация, посылаемая на экран с помощью функции printf().

ЗАМЕТКА: Хотя fprintf() u fscanf() часто являются наиболее простым способом записи и чтения данных из файла, они далеко не всегда являются наиболее эф­фективным решением. Поскольку отформатированные ASCII-данные сохраняются так же, как они выглядят на экране (а не в двоичном представлении), появляются дополнительные расходы при каждом вызове. Если скорость работы программы или размер создаваемых файлов играют важную роль, то, возможно, лучше ис­пользовать fread() и fwrite()

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]