Опубликован: 02.02.2011 | Уровень: для всех | Доступ: свободно
Лекция 22:

Прямой доступ к данным файла

< Лекция 21 || Лекция 22: 123 || Лекция 23 >
Аннотация: В лекции рассматриваются понятие, особенности, способы организации и функции ввода-вывода в файлы на нижнем уровне, отличия низкоуровневого и потокового ввода-вывода в файлы, примеры, иллюстрирующие низкоуровневый обмен данными в файлах.
Ключевые слова: файл, именованная область, информация, доступ, операции, открытый файл, форматирование, периферийное устройство, буферизация, преобразование данных, текстовый формат, указатель текущей позиции, файловый дескриптор, операции над файлами, стандартная библиотека, переносимость, синтаксис, filename, указатель, имя файла, путь, полный путь, обратный, управляющая последовательность, объединение, логический оператор, константы, конец файла, параметр, тип доступа к файлу, функция, значение, семантика, файловая система, алгоритм, системный вызов, запись, доступ к файлу, объект, размер файла, блок данных, дескриптор, ядро, счетчик, операционная система, индекс, дескриптор файла, сеанс, w-buffer, адрес, пользователь, адресное пространство, параметр функции, режимы ввода, буфер данных, запрос, чтение данных, коррекция, запись в файл, завершение процесса, org, позиционирование, Размещение, базовый тип, входные данные, диапазон, числовой тип, программа, задание на соответствие, абстракция данных, листинг программы

Цель лекции: изучить организацию ввода-вывода в файлы на нижнем уровне, научиться решать задачи с использованием прямого доступа к данным файла на языке C++.

Ввод-вывод низкого уровня

Файл представляет собой именованную область внешней памяти, в которой хранится информация в виде последовательности байтов. С такой точки зрения можно рассматривать любой произвольный файл, поэтому доступ к его содержимому иногда удобно организовать на нижнем уровне с помощью средств прямого доступа к данным.

Рассмотренные ранее средства обмена с файлами позволяют записывать и считывать данные только последовательно. Операции чтения-записи всегда производятся, начиная с текущей позиции в потоке. Начальная позиция устанавливается при открытии потока и может соответствовать начальному или конечному байту потока в зависимости от режима открытия файла. При этом данные потока буферизируются и выполняется форматирование передаваемой информации.

Функции ввода-вывода низкого уровня (прямого доступа) осуществляют обмен с файлами или периферийными устройствами путем прямого обращения к соответствующим функциям операционной системы (системным вызовам). Отличительные особенности средств прямого доступа к файлам следующие.

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

Основные функции низкого уровня

Функции низкого уровня, прототипы которых входят в стандартную библиотеку <io.h>, обычно применяются при разработке собственных подсистем ввода-вывода. Большинство функций этого уровня переносимы в рамках некоторых систем программирования на язык С или С++.

Функция открытия файла для чтения-записи

Для начала работы с файлом его необходимо открыть с помощью функции open.

Синтаксис:

int open(const char *filename, int oflags [,int sflags]);

где filenameуказатель на строку символов, представляющую собой допустимое имя файла, в которое может входить спецификация файла (включает обозначение логического устройства, путь к файлу и собственно имя файла). При указании полного пути в качестве разделителя используется символ "слэш" ('/'), а не "обратный слэш" ('\'), как принято. Это объясняется использованием символа "обратный слэш" в управляющих последовательностях в С++;

oflags – доступный тип операций, представляющий собой одну или несколько целочисленных констант, объявленных в файле <fcntl.h>. Если задана больше чем одна константа, тогда выполняется их объединение при помощи логического оператора ИЛИ ( | ). Состав доступных констант зависит от операционной системы. В таблице перечислены константы режима, встречающиеся практически во всех операционных системах.

Константы типа операций
Константа Описание
O_APPEND Добавление в конец файла. Указатель на файл перемещен в конец файла перед каждой операцией записи.
O_CREAT Новый файл создается и открывается для записи; не эффективно, если существует файл, определяемый по указанному имени.
O_EXCL Возвращается значение ошибки, если существует файл, определяемый по указанному имени. Применяется только вместе с O_CREAT.
O_RDONLY Файл открыт только для чтения; если задается этот флаг, может быть выбран либо флаг O_RDWR, либо O_WRONLY.
O_WRONLY Файл открыт только для записи; если задан этот флаг, должен быть задан также либо флаг O_RDONLY, либо O_RDWR.
O_RDWR Файл открыт одновременно для чтения и записи; если задается этот флаг, может быть выбран либо флаг O_RDONLY, либо O_WRONLY.
O_TRUNC Существующий файл открыт и усечен к длине 0; этот файл должен иметь разрешение на запись. Содержимое файла уничтожается.
O_BINARY Файл открыт в двоичном (не транслированном) режиме.
O_TEXT Файл открыт в текстовом (транслирующем) режиме.

sflags – необязательный параметр, который определяет тип доступа к файлу и представляет собой одну или несколько целочисленных констант, объявленных в файле <sys\stat.h>. Если задана больше чем одна константа, тогда выполняется их объединение при помощи логического оператора ИЛИ ( | ). Данный параметр применяется совместно с константой O_CREAT типа операций. Если открываемый файл существует, ТипДоступа игнорируется.

Константы типа доступа
Константа Описание
S_IWRITE Разрешена запись
S_IREAD Разрешено чтение
S_IREAD|S_IWRITE Разрешены чтение и запись

В случае успешного открытия файла данная функция возвращает неотрицательное целое значение, которое соответствует логическому номеру файла, а указатель устанавливается на начало файла. Максимальное число одновременно открытых файлов определяется константой HANDLE_MAX. При возникновении ошибки открытия файла функция возвращает значение -1.

Функция открытия файла для разделенного доступа

Семантика разделения означает, что файловая система должна определить алгоритм работы, который применяется, когда несколько клиентов одновременно обращаются к одному файлу. Важно, чтобы все изменения, сделанные одним клиентом, были бы видны другим клиентам, когда они выполняют следующий системный вызов на чтение или запись в один и тот же файл. Открытие файлов для разделенного доступа к ним выполняется с помощью функции sopen.

Синтаксис:

int sopen(const char *filename, int oflags, int shflags [,int sflags]);

где параметры filename, oflags, sflags имеют тот же смысл, что и в функции open.

shflags - устанавливаемый тип разделенного доступа к файлу, представляющий собой одну из целочисленных констант, объявленных в файле <fcntl.h>.

Константы типа разделения
Константа Описание
SH_COMPAT устанавливается режим совместимости
SH_DENYRW доступ по чтению и записи в файле не разрешен
SH_DENYWR доступ по записи в файле не разрешен
SH_DENYRD доступ по чтению в файле не разрешен
SH_DENYNO доступ по чтению и записи разрешен

В случае успешного открытия файла данная функция возвращает неотрицательное целое значение, которое соответствует логическому номеру файла, а указатель устанавливается на начало файла. При возникновении ошибки открытия файла функция возвращает значение -1.

Функция создания файла

Функция open предоставляет доступ к существующему файлу или создает его заново, а функция creat создает в файловой системе новый объект.

Синтаксис:

int creat(const char *filename, int sflags);

где параметры filename, sflags имеют тот же смысл, что и в функции open.

Если прежде в файловой системе не существовало объекта с указанным именем или полной спецификацией, будет создан новый файл с указанным именем и указанными правами доступа к нему. Если же такой файл уже существовал, размер файла усекается до 0 (освобождаются все существующие блоки данных и устанавливается размер файла равным 0). Созданный ранее файл должен при этом позволять производить запись в него, чтобы можно было создать "новый" файл с тем же самым именем.

Функция закрытия файла

После завершения работы с файлом его необходимо закрыть. Для этого используется функция close.

Синтаксис:

close(int fd);

где fd - дескриптор открытого файла.

Ядро выполняет операцию закрытия, используя дескриптор файла и информацию из соответствующих записей в таблице файлов и таблице индексов. Если счетчик ссылок в записи таблицы файлов имеет значение, большее, чем 1, то это означает, что на запись в таблице файлов делают ссылку другие пользовательские дескрипторы (например, при разделенном доступе). В этом случае счетчик ссылок уменьшается на 1. Если счетчик ссылок в таблице файлов имеет значение, равное 1, операционная система освобождает запись в таблице и индекс в памяти, ранее выделенный системной функцией open.

Когда выполнение функции close завершается, запись в таблице пользовательских дескрипторов файла становится пустой. Попытки процесса использовать данный дескриптор заканчиваются ошибкой до тех пор, пока дескриптор не будет переназначен другому файлу в результате выполнения другой функции. Когда выполнение программного кода завершается, система проверяет наличие активных пользовательских дескрипторов файла данного сеанса и закрывает каждый из них. Таким образом, ни один сеанс выполнения кода не может оставить файл открытым после своего завершения.

Функция чтения из файла

Чтение из файла на нижнем уровне осуществляется побайтно, без буферизации, с помощью функции read.

Синтаксис:

int read(int fd, char *buffer,int count);

где fd - дескриптор файла, возвращаемый функцией open ;

bufferадрес структуры данных, определенной пользователем, где будут размещаться считанные данные в случае успешного завершения выполнения функции read ;

count - количество байтов, которые определяет пользователь для считывания.

Функция возвращает количество фактически прочитанных байтов. В процессе выполнения функции ядро операционной системы обращается в таблице файлов к записи, которая соответствует значению пользовательского дескриптора файла, следуя за указателем. Затем оно устанавливает значения нескольких параметров ввода-вывода в адресном пространстве, тем самым устраняя необходимость в их передаче в качестве параметров функции. При выполнении режима ввода-вывода "чтение" формируются значения следующих параметров:

  • устанавливается флаг, свидетельствующий о том, что ввод-вывод направляется в адресное пространство структуры пользователя;
  • значению поля счетчика байтов присваивается количество байтов, которые должны быть прочитаны;
  • устанавливается адрес пользовательского буфера данных;
  • определяется значение смещения (из таблицы файлов), равное смещению в байтах внутри файла до места, откуда начинается ввод-вывод.

После считывания данные из блока копируются по назначенному адресу в структуру пользователя. При этом корректируются параметры ввода-вывода в адресном пространстве в соответствии с количеством прочитанных байтов: увеличивается значение смещения в байтах внутри файла и адрес структуры пользователя, куда будет доставлена следующая порция данных. Одновременно уменьшается число байтов, которые необходимо прочитать, чтобы выполнить запрос пользователя. Если запрос на чтение полностью не выполнен, происходит циклическое повторение описанных действий. Цикл завершается при достижении хотя бы одного из условий:

  • запрос на чтение выполнен полностью;
  • в файле больше нет данных (достигнут конец файла);
  • операционная система обнаружила ошибку при чтении данных с диска или при копировании данных в структуру пользователя.

В процессе чтения данных происходит коррекция значения смещения в таблице файлов в соответствии с количеством фактически прочитанных байтов; поэтому успешное выполнение операций чтения выглядит как последовательное считывание данных из файла.

< Лекция 21 || Лекция 22: 123 || Лекция 23 >
Денис Курбатов
Денис Курбатов
Выполнение каких функций не изменяет позицию указателя в файле?
Владислав Нагорный
Владислав Нагорный
Высшее образование
Сергей Гутько
Сергей Гутько
Россия, ВИУ, 2003