Чтение файла : системный вызов 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; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!