Произвольный доступ: системный вызов lseek() 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Произвольный доступ: системный вызов lseek()



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

Для изменения текущей позиции чтения-записи используется системный вызов lseek(). Ниже представлен его прототип.

off_t lseek (int fd, ott_t offset, int against);

Первый аргумент, как всегда, - файловый дескриптор. Второй аргумент - смещение, как положительное (вперед), так и отрицательное (назад). Третий аргумент обычно передается в виде одной из трех констант SEEK_SET, SEEK_CUR и SEEK_END, которые показывают, от какого места отсчитывается смещение. SEEK_SET - означает начало файла, SEEK_CUR - текущая позиция, SEEK_END - конец файла. Рассмотрим следующие вызовы:

lseek (fd, 0, SEEK_SET); lseek (fd, 20, SEEK_CUR); lseek (fd, -10, SEEK_END);

Первый вызов устанавливает текущую позицию в начало файла. Второй вызов смещает позицию вперед на 20 байт. В третьем случае текущая позиция перемещается на 10 байт назад относительно конца файла.

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

Я долго думал, какой бы пример придумать, чтобы продемонстрировать работу lseek() наглядным образом. Наиболее подходящим примером мне показалась идея создания программы рисования символами. Программа оказалась не слишком простой, однако если вы сможете разобраться в ней, то можете считать, что успешно овладели азами низкоуровневого ввода-вывода Linux. Ниже представлен исходный код этой программы.

/* draw.c */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> /* memset() */ #define N_ROWS 15 /* Image height */ #define N_COLS 40 /* Image width */ #define FG_CHAR 'O' /* Foreground character */ #define IMG_FN "image"  /* Image filename */ #define N_MIN(A,B) ((A)<(B)?(A):(B)) #define N_MAX(A,B) ((A)>(B)?(A):(B)) static char buffer[N_COLS]; void init_draw (int fd) {   ssize_t bytes_written = 0;   memset (buffer, ' ', N_COLS);   buffer [N_COLS] = '\n';   while (bytes_written < (N_ROWS * (N_COLS+1)))          bytes_written += write (fd, buffer, N_COLS+1); } void draw_point (int fd, int x, int y) {   char ch = FG_CHAR;   lseek (fd, y * (N_COLS+1) + x, SEEK_SET);   write (fd, &ch, 1); } void draw_hline (int fd, int y, int x1, int x2) {   size_t bytes_write = abs (x2-x1) + 1;   memset (buffer, FG_CHAR, bytes_write);   lseek (fd, y * (N_COLS+1) + N_MIN (x1, x2), SEEK_SET);   write (fd, buffer, bytes_write); } void draw_vline (int fd, int x, int y1, int y2) {   int i = N_MIN(y1, y2);   while (i <= N_MAX(y2, y1)) draw_point (fd, x, i++); } int main (void) {   int a, b, c, i = 0;   char ch;   int fd = open (IMG_FN, O_WRONLY | O_CREAT | O_TRUNC, 0644);   if (fd < 0) {          fprintf (stderr, "Cannot open file\n");          exit (1);   }   init_draw (fd);   char * icode[] = { "v 1 1 11", "v 11 7 11", "v 14 5 11",   "v 18 6 11", "v 21 5 10", "v 25 5 10", "v 29 5 6", "v 33 5 6",   "v 29 10 11", "v 33 10 11", "h 11 1 8", "h 5 16 17",   "h 11 22 24", "p 11 5 0", "p 15 6 0", "p 26 11 0", "p 30 7 0",   "p 32 7 0", "p 31 8 0", "p 30 9 0", "p 32 9 0", NULL };   while (icode[i]!= NULL) {   sscanf (icode[i], "%c %d %d %d", &ch, &a, &b, &c);          switch (ch) {                case 'v': draw_vline (fd, a, b, c); break;                case 'h': draw_hline (fd, a, b, c); break;                case 'p': draw_point (fd, a, b); break;                default: abort();          }          i++;   }   close (fd);   exit (0); }

Теперь разберемся, как работает эта программа. Изначально "полотно" заполняется пробелами. Функция init_draw() построчно записывает в файл пробелы, чтобы получился "холст", размером N_ROWS на N_COLS. Массив строк icode в функции main() - это набор команд рисования. Команда начинается с одной из трех литер: 'v' - нарисовать вертикальную линию, 'h' - нарисовать горизонтальную линию, 'p' - нарисовать точку. После каждой такой литеры следуют три числа. В случае вертикальной линии первое число - фиксированная координата X, а два других числа - это начальная и конечная координаты Y. В случае горизонтальной линии фиксируется координата Y (первое число). Два остальных числа - начальная координата X и конечная координата X. При рисовании точки используются только два первых числа: координата X и координата Y. Итак, функция draw_vline() рисует вертикальную линию, функция draw_hline() рисует горизонтальную линию, а draw_point() рисует точку.

Функция init_draw() пишет в файл N_ROWS строк, каждая из которых содержит N_COLS пробелов, заканчивающихся переводом строки. Это процедура подготовки "холста".

Функция draw_point() вычисляет позицию (исходя из значений координат), перемещает туда текущую позицию ввода-вывода файла, и записывает в эту позицию символ (FG_CHAR), которым мы рисуем "картину".

Функция draw_hline() заполняет часть строки символами FG_CHAR. Так получается горизонтальная линия. Функция draw_vline() работает иначе. Чтобы записать вертикальную линию, нужно записывать по одному символу и каждый раз "перескакивать" на следующую строку. Эта функция работает медленнее, чем draw_hline(), но иначе мы не можем.

Полученное изображение записывается в файл image. Будьте внимательны: чтобы разгрузить исходный код, из программы исключены многие проверки (read(), write(), close(), диапазон координат и проч.). Попробуйте включить эти проверки самостоятельно.

======================================================

3. int open(const char *filename, int access, unsigned mode)

4.int _rtl_open(const char *filename, int access)

Прототип:

io.h

Описание:

Функция ореn() является частью UNIX-подобной системы ввода/вывода и не определена в стан­дарте ANSI С.

В отличие от буферизированной системы ввода/вывода в UNIX-подобной системе предпочте­ние отдается использованию дескрипторов файлов типа int, а не указателей на FILE. Функция ореn() открывает файл с именем filename и устанавливает режим доступа к нему в соответствии со значением аргумента access. Аргумент access представляет собой комбинацию основного режима доступа и модификаторов.

Base Значение
O_RDONLY Открыть только для чтения
O_WRONLY Открыть только для записи
O_RDWR Открыть для чтения/записи

Выбрав одно из этих значений, можно объединить его, используя ИЛИ, с одним или большим количеством следующих модификаторов доступа:

Модификаторы доступа Значение
O_NDELAY Не используется; включен для совместимости с UNIX
O_APPEND Заставляет указатель файла переместиться в конец файла перед каждой операцией записи
O_CREAT Если файл не существует, создает его с атрибутами, установленными в соответствии со значением mode
O_TRUNC Если файл существует, урезает его до длины 0, но сохраняет атрибуты файла
O_EXCL При использовании с O_CREAT не будет создавать выходной файл, если файл с таким именем уже существует
O_BINARY Открывает двоичный файл
O_ТЕХТ Открывает текстовый файл

Аргумент mode требуется только при использовании модификатора O_CREAT. В этом случае mode может принимать одно из трех значений:

Mode Значение
S_IWRITE Доступ по записи
S_IREAD Доступ по чтению
S_IWRITE | S_IREAD Доступ по чтению/записи

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

ENOENT Файл не существует
EMFILE Слишком много открытых файлов
EACCESS Доступ запрещен
EINVACC Недействительный код доступа

Функция _rtl_open() имеет большее количество модификаторов режима доступа при работе под управлением Windows. Возможны следующие добавочные значения:

Access modifiers Значение
O_NOINHERIT Файл не передается программе-потомку
SH_COMPAT Допускаются другие операции, использующие SH_COMPAT
SH_DENYRW Только текущий дескриптор файла имеет доступ к файлу
SH_DENYWR Разрешен доступ к файлу только по чтению
SH_DENYRD Разрешен доступ к файлу только по записи
SH_DENYNO Разрешены и другие опции совместного использования, за исключением SH_COMPAT

 

Пример:

Обычно обращение к ореn() выглядит следующим образом:
if((fd=open(filename, mode)) == -1) {
printf("Cannot open file. \ n ");
exit (1);
}

 

 

========================================================

#include <fcntl.h> /* Not technically required, but needed on some UNIX distributions */#include <sys/types.h>#include <sys/stat.h>

A. Function Definition

int open(const char *path, int oflags);int open(const char *path, int oflags, mode_t mode);
Field Description
const char *path The relative or absolute path to the file that is to be opened.
int oflags A bitwise 'or' separated list of values that determine the method in which the file is to be opened (whether it should be read only, read/write, whether it should be cleared when opened, etc). See a list of legal values for this field at the end.
mode_t mode A bitwise 'or' separated list of values that determine the permissions of the file if it is created. See a list of legal values at the end.
return value Returns the file descriptor for the new file. The file descriptor returned is always the smallest integer greater than zero that is still available. If a negative value is returned, then there was an error opening the file.

B. Code Snippet

Example using the open system call:

#include <unistd.h>#include <fcntl.h> int main(){ int filedesc = open("testfile.txt", O_WRONLY | O_APPEND); if(filedesc < 0)   return 1;     if(write(filedesc,"This will be output to testfile.txt \ n", 36)!= 36) {   write(2,"There was an error writing to testfile.txt \ n"); // strictly not an error, it is allowable for fewer characters than requested to be written.   return 1; }     return 0;}

c. Available Values for oflag

Value Meaning
O_RDONLY Open the file so that it is read only.
O_WRONLY Open the file so that it is write only.
O_RDWR Open the file so that it can be read from and written to.
O_APPEND Append new information to the end of the file.
O_TRUNC Initially clear all data from the file.
O_CREAT If the file does not exist, create it. If the O_CREAT option is used, then you must include the third parameter.
O_EXCL Combined with the O_CREAT option, it ensures that the caller must create the file. If the file already exists, the call will fail.

d. Available Values for mode

Value Meaning
S_IRUSR Set read rights for the owner to true.
S_IWUSR Set write rights for the owner to true.
S_IXUSR Set execution rights for the owner to true.
S_IRGRP Set read rights for the group to true.
S_IWGRP Set write rights for the group to true.
S_IXGRP Set execution rights for the group to true.
S_IROTH Set read rights for other users to true.
S_IWOTH Set write rights for other users to true.
S_IXOTH Set execution rights for other users to true.

 

========================================================

OPEN                      #include <fcntl.h>          #include <sys\types.h>          #include <sys\stat.h>          #include <io.h>   требуется только для объявления                                      функций.          int open(pathname, oflag [[, pmode]]);          char *pathname;   path-имя файла          int oflag;        доступный тип операций          int pmode;        разрешенный тип доступа.                      Описание.                                                                            Функция open открывает файл, определяемый по path-имени, и    подготавливает его к последующему чтению или записи, что опреде-    ляется посредством oflag.                   Аргумент oflag является целым выражением, состоящим из ком-    бинации одной или более манифестных констант, объявленных в    <fcntl.h>. Если задана больше чем одна константа, тогда они объ-    единяются при помощи логического оператора ИЛИ (:).                   OFLAG                     ЗНАЧЕНИЕ                                   O_APPEND   Указатель на файл перемещен в конец                       файла перед каждой операцией записи.                                   O_CREAT    Новый файл создан и открыт для записи;                       это не эффективно, если существует                       файл, определяемый по path-имени.                                   O_EXCL     Возвращается значение ошибки, если                       существует файл, определяемый по path-                       имени. Применяется только вместе с                       O_CREATE.        O_RDONLY   Файл открыт только для чтения; если                       задается этот флаг, может быть выбран                       либо флаг O_RDWR, либо O_WRONLY.                                   O_RDWR     Файл открыт одновременно для чтения                       и записи; если задается этот флаг,                       может быть выбран либо флаг O_RDONLY,                       либо O_WRONLY.                                   O_TRUNC    Существующий файл открыт и усечен к                       длине 0; этот файл должен иметь                       разрешение на запись. Содержимое файла                       уничтожается.                                   O_WRONLY   Файл открыт только для чтения; если                       задан этот флаг, должен быть задан                       также либо флаг O_RDONLY, либо ORDWR.                                   O_BINARY   Файл открыт в двоичном (не трансли-                       рованном) режиме. (См. описание дво-                       ичного режима у функции fopen).                                   O_TEXT     Файл открыт в текстовом (трансли-                       рующем) режиме. (См. описание тексто-                       вого режима у функции fopen).                                      Замечание! O_TRUNC полностью уничтожает содержимое сущест-    вующего файла; поэтому нужно внимательно использовать эту конс-    танту.          Аргумент pmode требуется только тогда, когда определена    константа O_CREAT. Если файл существует, pmode игнорируется. В    противном случае pmode определяет разрешенные типы доступа для    файла, которые устанавливаются во время первого закрытия нового    файла.          Pmode - целое выражение, содержащее одну или обе манифест-        ные константы S_IREAD, S_IWRITE, объявленные в <sys\stat.h>. Когда             заданы обе константы, они объединяются логическим оператором ИЛИ    (:). Значение аргумента pmode приводится ниже.                   КОНСТАНТА       ЕЕ СМЫСЛОВОЕ ЗНАЧЕНИЕ                   S_IWRITE        разрешает запись.                   S_IREAD         разрешает чтение.        S_IREAD|S_IWRITE разрешают чтение и запись.           Если запись не разрешена, файл предназначен только для чте-    ния. В MS DOS все файлы открыты для чтения; для них не возможно    задать разрешение только на запись. Поэтому, модели S_IWRITE и    S_IREAD: S_IWRITE являются эквивалентными.          Функция open перед установкой разрешенного доступа прикла-    дывает текущую маску файла к pmode. (Подробно об этом описывается    у функции umask).                      Возвращаемое значение.                      Эта функция возвращает handle на созданный файл. Возвращае-    мое значение -1 указывает на ошибку; errno устанавливается в одно    из следующих значений.                   ЗНАЧЕНИЕ           ЕГО СМЫСЛ             EACCES    Заданное path-имя является директорием;                      или сделана попытка записать в файл,                      открытый только для чтения, или                      возникло sharing-нарушение. (Sharing-                      режим файла для операций не допускается.                      Версии MS DOS 3.0 и старше).                   EEXIST    Флаги O_CREAT и O_EXCL определены, но                      названный файл всегда существует.                                  EMFILE    Другие handle-ры файла не доступны, т.к.                      много открытых файлов.                                 ENOENT    Файл или path-имя не найдено.                См. также access, chmod, close, creat, dup, dup2, fopen,    sopen, umask.                   Пример:                   #include <fcntl.h>       #include <sys\types.h>       #include <sys\stat.h>       #include <io.h>       #include <stdlib.h>       main ()        {         int fh1, fh2;                  fh1 = open("data1", O_RDONLY);         if (fh1 == -1)             perror("open failed on input file");         fh2 = open("data2", O_WRONLY:O_TRUNC:O_CREAT,                             S_IREAD:S_IWRITE);         if (fh2 == -1)             perror("open failed on output file");        .        .         .        }.         fh1 = open("data1", O_RDONLY);         if (fh1 == -1)             perror("open failed on input file");.

 

========================================================



Поделиться:


Последнее изменение этой страницы: 2021-06-14; просмотров: 51; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.218.196.182 (0.02 с.)