Linux программирование в примерах | страница 86



>18  { "joe", "192837465", 81920 },

>19 };

>20

>21 int

>22 main(int argc, char **argv)

>23 {

>24  int fd;

>25  int i, j;

>26

>27  if (argc < 2) {

>28   fprintf(stderr, "usage: %s file\n", argv[0]);

>29   return 1;

>30  }

>31

>32  fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);

>33  if (fd < 0) {

>34   fprintf(stderr, "%s: %s: cannot open for read/write: %s\n",

>35    argv[0], argv[1], strerror(errno));

>36   return 1;

>37  }

>38

>39  j = sizeof(people) / sizeof(people[0]); /* число элементов */

Строки 27–30 гарантируют, что программа была вызвана правильно. Строки 32–37 открывают именованный файл и проверяют успешность открытия.

Вычисление числа элементов >j массива в строке 39 использует отличный переносимый трюк число элементов является размером всего массива, поделенного на размер первого элемента. Красота этого способа в том, что он всегда верен: неважно, сколько элементов вы добавляете в массив или удаляете из него, компилятор это выяснит. Он не требует также завершающей сигнальной метки; т.е. элемента, в котором все поля содержат нули, >NULL или т.п.

Работа осуществляется в цикле (строки 41–55), который отыскивает смещение байтов, приведенное в каждой структуре (строка 42), а затем записывает всю структуру (строка 49):

>41  for (i = 0; i < j; i++) {

>42   if (lseek(fd, people[i].pos, SEEK_SET) < 0) {

>43    fprintf(stderr, "%s: %s: seek error: %s\n",

>44     argv[0], argv[1], strerror(errno));

>45    (void)close(fd);

>46    return 1;

>47   }

>48

>49   if (write(fd, &people[i], sizeof(people[i])) != sizeof(people[i])) {

>50    fprintf(stderr, "%s: %s: write error: %s\n",

>51     argv[0], argv[1], strerror(errno));

>52    (void)close(fd);

>53    return 1;

>54   }

>55  }

>56

>57  /* здесь все нормально */

>58  (void)close(fd);

>59  return 0;

>60 }

Вот результаты запуска программы:

>$ ch04-holes peoplelist /* Запустить программу */

>$ ls -ls peoplelist /* Показать использованные размеры и блоки */

>16 -rw-r--r-- 1 arnold devel 81944 Mar 23 17:43 peoplelist

>$ echo 81944 / 4096 | bc -l /* Показать блоки, если нет дыр */

>20.00585937500000000000

Случайно мы знаем, что каждый дисковый блок файла использует 4096 байтов. (Откуда мы это знаем, обсуждается в разделе 5 4.2 «Получение информации о файле». Пока примите это как данное.) Финальная команда bc указывает, что файлу размером 81944 байтов нужен 21 дисковый блок. Однако, опция -s команды ls, которая сообщает нам, сколько блоков использует файл на самом деле, показывает, что файл использует лишь 16 блоков!