Чтение файла : системный вызов read()



 

Системный вызов read (), объявленный в файле unistd . h, позволяет читать данные из файла. В отличие от библиотечных функций файлового ввода-вывода, которые предоставляют возможность интерпретации считываемых данных. Можно, например, записать в файл следующее содержимое: 2006.

Теперь, используя библиотечные механизмы, можно читать файл по-разному:

fscanf(filep, "%s", buffer);

fscanf (filep, "%d", number);

Системный вызов read () читает данные в "сыром" виде, то есть как последовательность байт, без какой-либо интерпретации. Ниже представлен адаптированный прототип read ().

ssize _ t read ( int fd , void * buffer , size _ t count );

Первый аргумент - это файловый дескриптор. Здесь больше сказать нечего. Второй аргумент - это указатель на область памяти, куда будут помещаться данные. Третий аргумент - количество байт, которые функция read () будет пытаться прочитать из файла. Возвращаемое значение -количество прочитанных байт, если чтение состоялось и -1, если произошла ошибка. Хочу заметить, что если read () возвращает значение меньше count, то это не символизирует об ошибке.

Несколько слов о типах. Тип size _ t в Linux используется для хранения размеров блоков памяти. Какой тип реально скрывается за size _ t, зависит от архитектуры; как правило это unsigned long int или unsigned int. Тип ssize _ t (Signed SIZE Type) - это тот же size _ t, только знаковый. Используется, например, в тех случаях, когда нужно сообщить об ошибке, вернув отрицательный размер блока памяти. Системный вызов read () именно так и поступает.

Теперь напишем программу, которая просто читает файл и выводит его содержимое нa экран. Имя файла будет передаваться в качестве аргумента (argv [1]). Ниже приведен исходный код этой программы.

/* myread.c */

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/stat.h>

#include <sys/types.h>

int main (int argc, char ** argv)

{

int fd;

ssize_t ret;

char ch;

fd = open (argv[1], O_RDONLY);

if(fd<0)

{

fprintf (stderr, "Cannot open file\n");

exit(1);

}

while ((ret= read (fd, &ch, 1)) > 0)

{

putchar (ch);

}

if(ret<0)

{

fprintf (stderr, "myread: Cannot read file\n");

exit (1);

}

close ( fd );

exit (0);

}

В этом примере используется укороченная версия оре n (), так как файл открывается только для чтения. В качестве буфера (второй аргумент read ()) мы передаем адрес переменной типа char. По этому адресу будут считываться данные из файла (по одному байту за раз) и передаваться на стандартный вывод. Цикл чтения файла заканчивается, когда read () возвращает нуль (нечего больше читать) или -1 (ошибка). Системный вызов close () закрывает файл.

Как можно заметить, в нашем примере системный вызов read () вызывается ровно столько раз, сколько байт содержится в файле. Иногда это действительно нужно; но не здесь. Чтение-запись посимвольным методом (как в нашем примере) значительно замедляет процесс ввода-вывода за счет многократных обращений к системным вызовам. По этой же причине возрастает вероятность возникновения ошибки. Если нет действительной необходимости, файлы нужно читать блоками. Ниже приведен исходный код программы, которая делает то же самое, что и предыдущий пример, но с использованием блочного чтения файла. Размер блока установлен в 64 байта.

/* myread 1.с */

# include < stdlib . h >

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/stat.h>

#include <sys/types.h>

#define BUFFER_SIZE 64

int main (int argc, char ** argv)

{

int fd;

ssize_t read_bytes;

char buffer[BUFFER_SIZE+1];

fd = open (argv[1], O_RDONLY);

if(fd<0)

fprintf (stderr, "Cannot open file\n");

exit(1);

read_bytes = read (fd, buffer, BUFFER_SIZE)) > 0)

……………………………

fprintf (stderr, "myread: Cannot read file\n");

exit (1);

}

close ( fd );

exit (0);

}

Примечание: дополните самостоятельно недостающие строчки в программе myread 1.с.

Теперь можно примерно оценить и сравнить скорость работы двух примеров. Для этого надо выбрать в системе достаточно большой файл (бинарник ядра или видеофильм, например) и посмотреть на то, как быстро читаются эти файлы:

$ time ./myread /boot/vmlinuz > /dev/null

real 0m 1.443s

user 0m0.383s

sys 0ml.039s

$ time ./myread 1 /boot/vmiinuz > /dev/null

real 0m0.055s

user 0m0.010s

sys 0 m 0.023 s

$

Примечание: чтобы эти программы знали, какой именно файл следует открывать и читать, необходимо написать дополнительную (главную) программу, которая будет запрашивать имя этого файла и вызывать программу myread или myread 1. Или же можно вместо argv [1]  указать имя файла, заключенное в кавычки.

 

 


Дата добавления: 2019-03-09; просмотров: 438; Мы поможем в написании вашей работы!

Поделиться с друзьями:






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