| Расширенные возможности ввода-вывода в Linux |
|
Тут описываются дополнительные возможности низкоуровневого ввода-вывода в Linux: векторное чтение, векторная запись и концепция "черных дыр". Взаимодействие с библиотечными механизмамиБиблиотечные механизмы ввода-вывода языка С реализованы на основе системных вызовов. Это легко проверить с помощью очень полезной утилиты strace, которая запускает переданную ей программу и выводит в стандартный поток ошибок отчет об использованных системных вызовах. Чтобы перенаправить вывод этой программы в отдельный файл, указывается опция -о. Итак, чтобы проверить механизм в действии, напишем простую программу, выводящую на экран знаменитое приветствие "Hello World". Листинг 8.1. Программа hw.c #include <stdio.h> Теперь соберем программу и запустим ее с помощью утилиты strace: $ gcc -о hw hw.c Если теперь посмотреть содержимое файла report, то можно обнаружить, что даже такая простая программа задействует много системных вызовов. Но нас сейчас интересует лишь ввод-вывод: $ grep write report Что и требовалось доказать: функция printf о действительно вывела приветствие при помощи системного вызова write (). Возникает разумный вопрос: можно ли получить дескриптор файла из указателя file? Можно. Для этого предусмотрена функция f ileno(), объявленная в заголовочном файле stdio.h следующим образом: int fileno (FILE * FP); Эта функция возвращает дескриптор, соответствующий файловому указателю fp. В случае ошибки возвращается -1. Чтобы продемонстрировать работу функции f ileno о, рассмотрим простой пример, который выводит содержимое указанного файла на экран Пример fitenodemo.с #include <stdio.h> #include <unistd.h> #define AKR_SIZE(array) (sizeof(array)/sizeof(array[0])) char buffer[4096]; int main (int argc, char ** argv) { FILE * ifile; int fd; int nbytes; if (argc < 2) { fprintf (stderr, "Too few arguments\n"); return 1; } ifile = fopen (argvfl], "r"); if (ifile == NULL) { fprintf (stderr, "Cannot open file " "<%s)\n", argvtl]); return 1; } if ((fd = fileno (ifile)) == -1) { fprintf (stderr, "Cannot get descriptor\n"); return 1; } while ((nbytes = read (fd, buffer, ARR_SIZE (buffer))) > 0) write (1, buffer, nbytes); fclose (ifile); return 0; } Здесь важно понимать, что функция f close () освобождает дескриптор. Аналогичным образом, если вызвать системный вызов closed для дескриптора fd, то файловый указатель if Не будет считаться закрытым. Иногда требуется провести обратную процедуру, т. е. получить из дескриптора файловый указатель. Это можно сделать при помощи функции fdopen (), объявленной в заголовочном файле stdio.h: FILE * fdopen (int FD, const char * MODE); Эта функция возвращает файловый указатель, соответствующий открытому файлу с дескриптором fd. В случае ошибки возвращается null. Аргумент mode аналогичен соответствующему аргументу функции fopen (). Здесь важно следить, чтобы параметр mode не противоречил флагам, соответствующим дескриптору fd. Иными словами, если fd открыт только для чтения, то функция fdopen о не сможет создать файловый указатель, открытый только для записи. Следующая программа демонстрирует эту ошибку (листинг 8.3). Программа brokenfiie.с #include <stdio.h> #include <fcntl.h> int main (int argc, char ** argv) int fd; FILE * filep; if (argc < 2) { fprintf (stderr, "Too few arguments\n"); return 1; } fd = open (argvfl], 0_RDONLY); if (fd == -1) { fprintf (stderr, "Cannot open file " "(%s)\n", argv[1]); return 2; } filep = fdopen (fd, "w"); if (filep == NULL) { fprintf (stderr, "Cannot create file pointer\n") return 3; } close (fd); return 0; } Эта программа завершается ошибкой. Рассмотрим теперь корректный пример, который выводит содержимое файла, используя библиотечные функции fgetc () и fputc (). Пример fdopendemo.c #include <stdio.h> #include <fcntl.h> int main (int argc, char ** argv) { int fd; FILE * ifile; char ch; if (argc < 2) { fprintf (stderr, "Too few arguments\n"); return 1; } fd = open (argv[lb 0_RDONLY) ; if (fd == -1} { fprintf (stderr, "Cannot open file " "(%s)\n", argv[1]); return 2; } ifile = fdopen (fd, "r"); if (ifile == NULL) { fprintf (stderr, "Cannot create file pointer\n"); return 3; } while ((ch = fgetc (ifile)) != EOF) fputc (ch, stdout); close (fd); return 0; } Ввод-вывод осуществляется посимвольно. Попробуйте самостоятельно переделать эту программу так, чтобы данные читались и записывались через буфер.
Related Articles
Set as favorite
Bookmark
Email This
Hits: 378 Комментарии (0)RSS feed CommentsНаписать комментарий |