Если файл уже открыт для чтения или записи, лучше пользоваться функцией fstat()
. В качестве первого аргумента она принимает не путевое имя, а дескриптор.
В листинге Б.6 показана функция которая создает буфер достаточного размера и загружает в него содержимое указанного файла. Размер файла определяется с помощью функции fstat()
. Она же позволяет проверить, соответствует ли заданное имя обычному файлу.
Листинг Б.6. ( read-file.c ) Загрузка файла в буфер
#include
#include
#include
#include
#include
/* Загрузка содержимого файла FILENAME в память.
Размер буфера записывается в аргумент LENGTH.
Создаваемый буфер должен удаляться в вызывающей функции.
Если аргумент FILENAME не соответствует обычному файлу,
возвращается NULL. */
char* read_file(const char* filename, size_t* length) {
int fd;
struct stat file_info;
char* buffer;
/* Открытие файла. */
fd = open(filename, O_RDONLY);
/* Получение информации о файле. */
fstat(fd, &file_info);
*length = file_info.st_size;
/* Проверка того, что это обычный файл. */
if (!S_ISREG(file_info.st_mode)) {
/* Этот тип файла не поддерживается. */
close(fd);
return NULL;
}
/* выделение буфера достаточного размера. */
buffer = (char*)malloc(*length);
/* Загрузка файла в буфер. */
read(fd, buffer, *length);
/* Конец работы. */
close(fd);
return buffer;
}
Б.3. Векторные чтение и запись
Аргументами функции write()
являются указатель на буфер и длина буфера. Эта функция записывает в файл непрерывный блок данных, хранящихся в памяти. Но программам часто требуется записывать группы блоков, хранящихся по разным адресам. Если использовать функцию write()
, придется либо предварительно объединять блоки в памяти, что неэффективно, либо многократно вызывать функцию. Последнее тоже не всегда приемлемо. Например, при записи в сокет два вызова функции write()
приведут к отправке в сеть двух пакетов, тогда как те же самые данные можно перестать в одном пакете.
Функция writev()
позволяет записать в файл несколько несвязанных буферов одновременно. Это называется векторной записью . Сложность применения функции writev()
заключается в создании структуры, задающей начало и конец каждого буфера. Эта структура представляет собой массив элементов типа struct iovec
. Каждый элемент описывает одну область памяти. В поле iov_base
указывается адрес начала области, а в поле iov_len
— ее длина. Если число буферов известно заранее, можно просто объявить массив типа struct iovec
. В противном случае придется выделять массив динамически.
Функции writev()
передается дескриптор записываемого файла, массив структур iovec и размер массива. Функция возвращает общее число записанных байтов.
Программа, показанная в листинге Б.7, записывает свои аргументы командной строки в файл с помощью одной-единственной функции writev()
. Первый аргумент — это имя файла, в котором сохраняются все последующие аргументы, каждый в отдельной строке. Число элементов в массиве структур iovec
в два раза превышает число аргументов командной строки, так как после каждого аргумента записывается символ новой строки. Поскольку количество аргументов неизвестно заранее, массив создается с помощью функции malloc()
.
Листинг Б.7. ( write-args.c ) Запись списка аргументов в файл с помощью функции writev()
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[]) {
int fd;
struct iovec* vec;
struct iovec* vec_next;
int i;
/* Символ новой строки хранится в обычной переменной
типа char. */
char newline = '\n';
/* Первый аргумент командной строки -- это имя выходного
файла. */
char* filename = argv[1];
/* Пропускаем первые два элемента списка аргументов.
Элемент номер 0 -- это имя самой программы,
а элемент номер 1 -- это имя выходного файла */
argc -= 2;
argv += 2;
/* Выделяем массив элементов типа iovec каждому аргументу
командной строки соответствует два элемента массива:
один -- для самого аргумента,
а другой -- для символа новой строки. */
vec =
(struct iovec*)malloc(2 * argc * sizeof(struct iovec));
/* Просмотр списка аргументов и создание массива. */
Читать дальше