Skip to content

Home Программирование Чтение файла: read()
Чтение файла: read()

Для чтения файлов служит системный вызов reado, объявленный в файле unistd.h следующим образом:

ssize_t read (int FD, void * BUFFER, size„t SIZE);

Этот системный вызов пытается прочитать size байт из файла с дескриптором fd. Прочитанная информация заносится в buffer. Возвращаемое значение — число реально прочитанных байтов.

Аргумент size_t — это беззнаковый целый тип, размерность которого зависит от реализации, ssize_t тоже является целым, но уже знаковым типом. Указание именно ssize_t обусловлено тем, что read() возвращает -1 в случае ошибки. Когда текущая позиция ввода-вывода достигает конца файла, read() возвращает 0.

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

Программа readl.c

#include <stdio.h> 
#include <fcntl.h>
#include <unistd.h>
int main (int argc, char ** argv)
{
int fd;
char ch;
if (argc < 2)
{
fprintf (stderr, "Too few arguments\n");
return 1;
}
fd = open (argvtl], 0_RDONLY);
if (fd == -1)
{
fprintf (stderr, "Cannot open file (%s)\n", argv[1]);
return 1;
}
while (read (fd, &ch, 1) > 0) printf ("%c", ch);
if (close (fd) == -1)
{
fprintf (stderr, "Cannot close file""with descriptor=%d\n", fd);
return 1;
return 0;
}

Итак, в качестве буфера был передан адрес переменной типа char, и чтение осуществлялось по одному байту. Такая схема проста, но очень неэффективна. Обращение к системному вызову read О для чтения каждого символа значительно замедляет работу программы. Только представьте себе: чтобы прочитать файл размером 1 Кбайт, программа обращается к ядру 1024 раза! Поэтому файлы лучше читать достаточно большими блоками. Обычно для этих целей создается буфер размером в несколько килобайт.

Напишем теперь программу, которая делает то же, что и предыдущая, только более эффективным способом

Программа read2.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#define BUF_SIZE 4096 char buffer[BUF_SIZE+1];
int main (int argc, char ** argv)
{
ssize_t bytes;
int fd;
if (argc < 2)
{
fprintf (stderr, "Too few arguments\n");
return 1;
}
fd = open ( argv[1], 0_KDONLY);
if (fd == -1)
{
fprintf (stderr, "Cannot open file (%s)\n",argv[1]);
return 1;
}
while ((bytes = read (fd, buffer, BUF_SIZE)) > 0)
{
buffer [bytes] = 0;
printf <"%s", buffer);
}
close (fd);
return 0;
}

В этой версии программы появилась новая переменная bytes, в которую записывается размер прочитанной информации. Буфером является массив buffer. Обратите внимание, что каждый раз в конец этого массива дописывается нуль-терминатор. Это обусловлено тем, что вывод осуществляется функцией printf о, для которой признаком окончания вывода служит символ с кодом 0. Всегда следует помнить, что системный вызов read() просто читает байты, а ответственность за формирование строки возложена на программиста.

Функция printf о предназначена для вывода данных на экран терминала. Поэтому она не может воспринимать некоторые байты "как есть". Рассмотрим следующую команду:

$ ./readl fool > foo2

В этом случае файл fool будет скопирован в foo2, если исходный файл не содержит определенные символы, которые printf о воспринимает как команды форматирования (звонок, символ с кодом 0 и т. д.). В связи с этим, программа readl не может быть универсальным средством копирования файлов.

Напишем еще одну программу, упрощенную версию утилиты ср, которая будет осуществлять полноценное копирование файла

Программа копирования файлов

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#define BUF_SIZE 4096 char buffer [BUF_SIZE];
int main (int argc, char ** argv)
{
int ifd, i;
FILE * outfile;
ssize_t bytes;
if (argc < 3)
{
fprintf (stderr, "Too few arguments\n");
return 0;
}
ifd = open ( argv[1], 0_RDONLY);
if (ifd == -1)
{
fprintf (stderr, "Cannot open input file " "(%s)\n\ argv[1]);
return 1;
}
outfile = fopen (argv[2], "w");
if (outfile == NULL)
{
fprintf (stderr, "Cannot open output file " "(%s)\n\ argv[2]);
return 1;
}
while ((bytes = read (ifd, buffer, BUF_SIZE)) > 0)
{
for (i = 0; i < bytes; i++) fputc (buffer[i], outfile);
}
close (ifd);
fclose (outfile);
return 0;

 

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

Комментарии (0)

RSS feed Comments

Написать комментарий

smaller | bigger

busy
 

Регистрация




Top