Прямой доступ к данным файла
Функция записи в файл
Запись в файл на нижнем уровне осуществляется побайтно, без буферизации, с помощью функции write.
int write(int fd, char *buffer,int count);
где переменные fd, buffer, count имеют тот же смысл, что и для вызова функции read.
Функция возвращает количество фактически переданных байтов.
Алгоритм записи в файл похож на алгоритм чтения: указатель циклически перемещается в соответствии с количеством переданных в файл байтов до завершения процесса передачи данных в файл. Когда запись завершается, операционная система корректирует размер файла.
Функция прямого доступа к файлу
Функция read при корректном выполнении осуществляет последовательное чтение данных из файла. Однако при работе с файлами на нижнем уровне можно изменять порядок доступа к данным с последовательного на произвольный. Для этого используется функция fseek.
int fseek(FILE *f, long off, int org);
off – позиция смещения;
org – начало отсчета.
Смещение off задается выражением или переменной и может быть отрицательным, то есть возможно перемещение как в прямом, так и в обратном направлениях. Начало отсчета org задается одной из определенных в файле <stdio.h> констант.
Константа | Значение | Описание |
---|---|---|
SEEK_SET | 0 | начало файла |
SEEK_CUR | 1 | текущая позиция |
SEEK_END | 2 | конец файла |
Функция возвращает 0, если перемещение в потоке выполнено успешно, иначе возвращает ненулевое значение.
Функцию fseek следует использовать только при работе с двоичными файлами. В текстовых файлах начало отсчета org должно быть установлено как SEEK_SET, а смещение указывается относительно начала файла (возможно нулевое смещение, которое интерпретируется как позиционирование в начало файла).
Например, для текстовых файлов:
fseek(f,0L,SEEK_SET); //перемещение к началу потока из текущей позиции fseek(f,0L,SEEK_END); //перемещение к концу потока из текущей позиции
Например, для двоичных файлов:
fseek(f,(long)sizeof(a),SEEK_SET); //перемещение вперед от начала на длину переменной а fseek(f,-(long)sizeof(a),SEEK_CUR); //перемещение назад от текущей позиции на длину переменной а
Кроме этой функции, для прямого доступа к файлу используются функции:
long ftell(FILE *f); //получает значение указателя текущей позиции в потоке void rewind(FILE *f); //устанавливает значение указателя на начало потока
Пример 1. Использование в программе функций доступа к данным на нижнем уровне.
#include "stdafx.h" #include <iostream> using namespace std; #include <fcntl.h> #include <sys\stat.h> #include <io.h> int _tmain(int argc, _TCHAR* argv[]){ int fh1, fh2; //открытие файла на нижнем уровне fh1 = open("data1.dat", O_RDONLY); //проверка корректности открытия файла if (fh1 == -1) perror("Open failed on input file"); fh2 = open("data2.dat",O_WRONLY|O_TRUNC|O_CREAT,S_IREAD|S_IWRITE); if (fh2 == -1) perror("Open failed on output file"); system("pause"); return 0; }
Пример 2. Использование в программе позиционирования файлового указателя с помощью функции fseek в двоичном файле.
#include "stdafx.h" #include <iostream> using namespace std; #include <io.h> int _tmain(int argc, _TCHAR* argv[]){ FILE *f;//указатель на двоичный файл int i,n=10; char s[]="String"; float r; f=fopen("file_bin","wb"); //создание двоичного файла для записи for(i=1;i<=n;i++){ r=pow(i,1.0/3); fwrite(s,sizeof(s),1,f); //запись строки String в файл fwrite(&i,sizeof(int),1,f); //запись целого числа (номера строки) в файл fwrite(&r,sizeof(float),1,f); //запись вещественного числа (корня кубического) в файл printf("\n%s %d %f",s,i,r);//контрольный вывод на экран } fclose(f);//закрытие файла printf("\n"); f=fopen("file_bin","rb"); //открытие двоичного файла для чтения for(i=n; i>0; i--) { //перемещение указателя файла fseek(f,(i-1)*(sizeof(s)+sizeof(int)+sizeof(float)),SEEK_SET); fread(&s,sizeof(s),1,f);//чтение строки fread(&n,sizeof(int),1,f);//чтение целого числа fread(&r,sizeof(float),1,f); //чтение вещественного числа printf("\n%s %d %f",s,n,r); //вывод на экран содержимого файла } system("pause"); return 0; }
Ключевые термины
Дескриптор – это целое значение, характеризующее размещение информации об открытом файле во внутренних таблицах операционной системы.
Прямой доступ к файлу – это доступ к содержимому файла с помощью средств операционной системы.
Разделенный доступ к файлу – это организация работы с одним и тем же файлом нескольких пользователей одновременно.
Смещение – это относительная координата перемещения указателя при обращении к данным файла на нижнем уровне.
Тип доступа – это разрешенное действие над файлом, оформленное с помощью целочисленных констант.
Тип операций – это выполняемая операция над файлом, оформленная с помощью целочисленных констант.
Функции ввода-вывода низкого уровня (прямого доступа) – это функции, осуществляющие обмен с файлами или периферийными устройствами путем прямого обращения к соответствующим функциям операционной системы.
Краткие итоги
- В С++ доступ к файлам можно осуществлять на потоковом и низком уровнях.
- В отличие от потокового уровня, низкоуровневый ввод-вывод осуществляется побайтно без буферизации данных, без приведения их к базовым типам и использует ресурсы операционной системы.
- Работа с файлами на низком уровне осуществляется с помощью средств прямого доступа к данным файла.
- Открытому файлу на нижнем уровне соответствует файловый дескриптор.
- Режимы доступа к данным файла на нижнем уровне определяются с помощью констант типа доступа и типа операций.
- В С++ предусмотрен разделенный режим работы с файлами на нижнем уровне.
- Открытый файл должен быть закрыт после использования.
- Порядок доступа к байтам файла можно изменять функционально путем указания относительного смещения. Смещение может быть положительным (движение к концу файла), отрицательным (движение к началу файла) или нулевым (нет смещения).
- Запрос на чтение данных на нижнем уровне завершается при считывании заданного числа байтов, при достижении конца файла или при возникновении системной ошибки чтения.