Прямой доступ к данным файла
Функция записи в файл
Запись в файл на нижнем уровне осуществляется побайтно, без буферизации, с помощью функции 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;
}Ключевые термины
Дескриптор – это целое значение, характеризующее размещение информации об открытом файле во внутренних таблицах операционной системы.
Прямой доступ к файлу – это доступ к содержимому файла с помощью средств операционной системы.
Разделенный доступ к файлу – это организация работы с одним и тем же файлом нескольких пользователей одновременно.
Смещение – это относительная координата перемещения указателя при обращении к данным файла на нижнем уровне.
Тип доступа – это разрешенное действие над файлом, оформленное с помощью целочисленных констант.
Тип операций – это выполняемая операция над файлом, оформленная с помощью целочисленных констант.
Функции ввода-вывода низкого уровня (прямого доступа) – это функции, осуществляющие обмен с файлами или периферийными устройствами путем прямого обращения к соответствующим функциям операционной системы.
Краткие итоги
- В С++ доступ к файлам можно осуществлять на потоковом и низком уровнях.
- В отличие от потокового уровня, низкоуровневый ввод-вывод осуществляется побайтно без буферизации данных, без приведения их к базовым типам и использует ресурсы операционной системы.
- Работа с файлами на низком уровне осуществляется с помощью средств прямого доступа к данным файла.
- Открытому файлу на нижнем уровне соответствует файловый дескриптор.
- Режимы доступа к данным файла на нижнем уровне определяются с помощью констант типа доступа и типа операций.
- В С++ предусмотрен разделенный режим работы с файлами на нижнем уровне.
- Открытый файл должен быть закрыт после использования.
- Порядок доступа к байтам файла можно изменять функционально путем указания относительного смещения. Смещение может быть положительным (движение к концу файла), отрицательным (движение к началу файла) или нулевым (нет смещения).
- Запрос на чтение данных на нижнем уровне завершается при считывании заданного числа байтов, при достижении конца файла или при возникновении системной ошибки чтения.