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



возвращает 0, это означает, что достигнут конец файла.

Теперь мы можем показать оставшуюся часть кода для >ch04-cat. Процедура >process() использует 0 для стандартного ввода, если именем файла является «>-» (строки 50 и 51). В противном случае она открывает данный файл:

>36 /*

>37   * process --- сделать что-то с файлом, в данном случае,

>38   * послать его в stdout (fd 1).

>39   * Возвращает 0, если все нормально; в противном случае 1.

>40   */

>41

>42 int

>43 process(char *file)

>44 {

>45  int fd;

>46  ssize_t rcount, wcount;

>47  char buffer[BUFSIZ];

>48  int errors = 0;

>49

>50  if (strcmp(file, "-") == 0)

>51   fd = 0;

>52  else if ((fd = open(file, O_RDONLY)) < 0) {

>53   fprintf(stderr, "%s: %s: cannot open for reading: %s\n",

>54    myname, file, strerror(errno));

>55   return 1;

>56  }

Буфер >buffer (строка 47) имеет размер >BUFSIZ; эта константа определена В > как «оптимальный» размер блока для ввода/вывода. Хотя значение >BUFSIZ различается в разных системах, код, использующий эту константу, чистый и переносимый.

Основой процедуры является следующий цикл, который повторно читает данные до тех пор, пока не будет достигнут конец файла или не возникнет ошибка.

>58 while ((rcount = read(fd, buffer, sizeof buffer)) > 0) {

>59  wcount = write(1, buffer, rcount);

>60  if (wcount != rcount) {

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

>62    myname, file, strerror(errno));

>63   errors++;

>64   break;

>65  }

>66 }

Переменные >rcount и >wcount (строка 45) имеют тип >ssize_t, «знаковый >size_t», который позволяет хранить в них отрицательные значения. Обратите внимание, что число байтов, переданное >write(), является значением, возвращенным >read() (строка 59). Хотя мы хотим читать порциями фиксированного размера в >BUFSIZ, маловероятно, что размер самого файла кратен >BUFSIZ. При чтении из файла завершающей, меньшей порции байтов, возвращаемое значение указывает, сколько байтов buffer получили новые данные. В стандартный вывод должны быть скопированы только эти байты, а не весь буфер целиком.

Условие '>wcount != rcount' в строке 60 является правильным способом проверки на ошибки; если были записаны некоторые, но не все данные, >wcount будет больше нуля, но меньше >rcount.

В заключение >process() проверяет наличие ошибок чтения (строки 68–72), а затем пытается закрыть файл. В случае (маловероятном) неудачного завершения >close() (строка 75) она выводит сообщение об ошибке. Избежание закрытия стандартного ввода не является абсолютно необходимым в данной программе, но является хорошей привычкой при разработке больших программ, в случае, когда другой код где-то в другом месте хочет что-то с ним делать или если порожденная программа будет наследовать его. Последний оператор (строка 82) возвращает 1, если были ошибки, и 0 в противном случае.