![]() Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву ![]() Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Произвольный доступ: системный вызов 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 представляет собой комбинацию основного режима доступа и модификаторов.
Выбрав одно из этих значений, можно объединить его, используя ИЛИ, с одним или большим количеством следующих модификаторов доступа:
Аргумент mode требуется только при использовании модификатора O_CREAT. В этом случае mode может принимать одно из трех значений:
В случае успеха ореn() возвращает положительное целое число, являющееся дескриптором открытого файла. Возврат —1 означает, что файл не может быть открыт. В этом случае errno устанавливается в одно из следующих значений:
Функция _rtl_open() имеет большее количество модификаторов режима доступа при работе под управлением Windows. Возможны следующие добавочные значения:
Пример: Обычно обращение к ореn() выглядит следующим образом:
======================================================== #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);
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
d. Available Values for mode
======================================================== 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; просмотров: 69; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.221.136.116 (0.009 с.) |