Выбрать главу

 /* Просмотр списка аргументов и создание массива. */

 vec_next = vec;

 for (i = 0; i < argc; ++i) {

  /* первый элемент -- это текст аргумента */

  vec_next->iov_base = argv[i];

  vec_next->iov_len = strlen(argv[i]);

  ++vec_next;

  /* Второй элемент -- это символ новой строки, допускается,

     чтобы несколько элементов массива указывали на одну и

     ту же область памяти. */

  vec_next->iov_base = &newline;

  vec_next->iov_len = 1;

  ++vec_next;

 }

 /* Запись аргументов в файл. */

 fd = open(filename, O_WRONLY | O_CREAT);

 writev(fd, vec, 2 * argc);

 close(fd);

 free(vec);

 return 0;

}

Вот пример работы программы:

% ./write-args outputfile "first arg" "second arg" "third arg"

% cat outputfile

first arg

second arg

third arg

В Linux имеется также функция readv(), которая загружает содержимое файла в несколько несвязанных областей памяти. Как и в функции writev(), массив структур типа iovec определяет начало и размер каждой области.

Б.4. Взаимосвязь с библиотечными функциями ввода-вывода

Выше уже говорилось о том. что функции ввода-вывода стандартной библиотеки языка С реализованы на основе низкоуровневых функций. Иногда удобнее работать с одними, иногда — с другими.

Если файл был открыт с помощью функции fopen(), то узнать его дескриптор позволяет функция fileno(). Она принимает аргумент типа FILE* и возвращает соответствующий ему дескриптор. Например, можно открыть файл с помощью библиотечной функции fopen(), но осуществить в него запись посредством функции writev():

FILE* stream = fopen(filename, "w");

int file_descriptor = fileno(stream);

writev(file_descriptor, vector, vector_length);

Учтите, что переменные stream и file_descriptor соответствуют одному и тому же открытому файлу. Если выполнить следующую функцию, дескриптор file_descriptor станет недействительным:

fclose(stream);

Аналогичным образом следующая функция делает недействительным файловый указатель stream:

close(file_descriptor);

Чтобы получить файловый указатель, соответствующий дескриптору, воспользуйтесь функцией fdopen(). Ее аргументами является дескриптор и строка, определяющая режим создания файлового потока. Синтаксис строки аналогичен синтаксису второго аргумента функции fopen(), а задаваемый режим должен быть совместим с режимом открытия файла. Например, файлу, открытому для чтения, соответствует режим r, а файлу, открытому для записи, — режим w. Как и в случае функции fileno(), файловый указатель и дескриптор ссылаются на один и тот же файл, поэтому закрытие одного сделает недействительным другой.

Б.5. Другие низкоуровневые операции

Есть ряд других полезных функций для работы с файлами и каталогами.

■ Функция getcwd() возвращает имя текущего каталога. Она принимает два аргумента — указатель на буфер и длину буфера — и копирует имя каталога в буфер.

■ Функция chdir() делает текущим заданный каталог.

■ Функция mkdir() создает новый каталог. Ее первым аргументом является путевое имя каталога. Второй аргумент задает права доступа к каталогу. Интерпретация этого аргумента такая же, как и третьего аргумента функции open(). На итоговый код доступа влияет значение umask процесса.

■ Функция rmdir() удаляет указанный каталог.

■ Функция unlink() удаляет файл. Ее аргументом является путевое имя файла. С помощью этой функции можно удалять и другие объекты файловой системы, например именованные каналы и файлы устройств.

В действительности функция unlink() не обязательно удаляет содержимое файла. Как подсказывает ее имя, она удаляет из каталога ссылку на файл. Файл не будет больше фигурировать в списке содержимого каталога, но если какой-то процесс владеет открытым дескриптором этого файла, то содержимое файла не удаляется с диска. Это произойдет только тогда, когда не останется открытых дескрипторов файла. Так что если один процесс откроет файл для чтения или записи, а второй процесс в это время удалит ссылку на файл и создаст новый файл с таким же именем, первый процесс продолжит работать со старым содержимым файла. Чтобы получить доступ к новому содержимому первому процессу придется закрыть и повторно открыть файл.

■ Функция rename() переименовывает или перемещает файл. Двумя ее аргументами являются старое и новое путевые имена. Если путевые имена ссылаются на разные каталоги, функция перемещает файл (при условии, что он остается в той же файловой системе). С помощью функции rename() можно перемещать также каталоги и другие объекты файловой системы.