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 блоков!