Б.1.3. Запись данных

Б.1.3. Запись данных

Для записи данных в файл предназначена функция write(). Она принимает дескриптор файла, указатель на буфер данных и число записываемых байтов. Файл должен быть открыт для записи. Функция write() работает не только с текстовыми данными, но и с произвольными байтами.

В листинге Б.2 показана программа, которая записывает в указанный файл значение текущего времени. Если файл не существует, он создается. Для получения и форматирования значения времени программа использует функции time(), localtime() и asctime().

Листинг Б.2. (timestamp.c) Запись в файл метки времени

#include <fcntl.h>

#include <stdio.h>

#include <string.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <time.h>

#include <unistd.h>

/* Эта строка возвращает строку, содержащую значение

   текущих даты и времени. */

char* get_timestamp() {

 time_t now = time(NULL);

 return asctime(localtime(&now));

}

int main(int argc, char* argv[]) {

 /* Файл, в который записывается метка времени. */

 char* filename = argv[1];

 /* Получение метки времени. */

 char* timestamp = get_timestamp();

 /* Открытие файла для записи. Если файл существует, он

    открывается в режиме добавления; в противном случае

    файл создается. */

 int fd =

  open(filename. O_WRONLY | O_CREAT | O_APPEND, 0666);

 /* Вычисление длины строки с меткой времени. */

 size_t length = strlen(timestamp);

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

 write(fd, timestamp, length);

 /* Конец работы. */

 close(fd);

 return 0;

}

Вот как работает программа:

% ./timestamp tsfile

% cat tsfile

The Feb 1 23:25:20 2001

% ./timestamp tsfile

% cat tsfile

Thu Feb 1 23:25:20 2001

Thu Feb 1 23:25:47 2001

Обратите внимание на то, что при первом вызове программы timestamp файл был создан, а при втором вызове — дополнен.

Функция write() возвращает число записанных байтов или -1, если произошла ошибка. Для некоторых типов файлов чисто фактически записанных байтов может оказаться меньше требуемого. Программа должна выявлять подобные случаи и вызывать функцию write() повторно, чтобы передать оставшуюся часть данных. Этот прием продемонстрирован в листинге Б.3. Но иногда даже таких методов недостаточно. Например, если показанная функция будет записывать данные в сокет, в нее придется добавить код проверки того, не произошел ли в ходе операции записи разрыв соединения.

Листинг Б.3. (write-all.c) Запись буфера

/* Запись указанного числа байтов (COUNT) из буфера BUFFER

   в файл FD. В случае ошибки возвращается -1,

   иначе -- число записанных байтов. */

ssize_t write_all(int fd, const void* buffer, size_t count) {

 size_t left_to_write = count;

 while (left_to_write > 0) {

  size_t written = write(fd, buffer, count);

  if (written == -1)

   /* Произошла ошибка, завершаем работу. */

   return -1;

  else

   /* подсчитываем число оставшихся байтов. */

   left_to_write -= written;

 }

 /* Нельзя записать больше, чем COUNT байтов! */

 assert(left_to_write == 0);

 /* Число записанных байтов равно COUNT. */

 return count;

}