KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Марк Митчелл - Программирование для Linux. Профессиональный подход

Марк Митчелл - Программирование для Linux. Профессиональный подход

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Марк Митчелл, "Программирование для Linux. Профессиональный подход" бесплатно, без регистрации.
Перейти на страницу:

  /* Произошла ошибка. Выводим сообщение и завершаем работу. */

  perror("open");

  return 1;

 }

 return 0;

}

Результаты работы программы будут такими:

% ./create-file testfile

% ls -l testfile

-rw-rw-r-- 1 samuel users 0 Feb 1 22:47 testfile

% ./create-file testfile

open: File exists

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

Б.1.2. Закрытие файла

По окончании работы с файлом его следует закрыть с помощью функции close(). В ряде случаев, например в программе, показанной в листинге Б.1, нет необходимости вызывать данную функцию явно, так как ОС Linux автоматически закрывает все открытые файлы по завершении программы. Естественно, после того как файл был закрыт, обращаться к нему нельзя.

Закрытие файла вызывает разную реакцию операционной системы, в зависимости от природы файла. Например, когда закрывается сокет, происходит разрыв сетевого соединения между двумя компьютерами, взаимодействующими через сокет.

Linux ограничивает число файлов, которые могут быть открыты процессом в определенный момент времени. Дескрипторы открытых файлов занимают ресурсы ядра, поэтому желательно вовремя закрывать файлы, чтобы дескрипторы удалялись из системных таблиц. Обычно процессам назначается лимит в 1024 дескриптора. Изменить это значение позволяет системный вызов setrlimit() (см. раздел 8.5, "Функции getrlimit() и setrlimit(): лимиты ресурсов").

Б.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;

}

Б.1.4. Чтение данных

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

Чтение текстовых файлов DOS/Windows

В Linux-программах нередко приходится читать файлы, созданные в DOS или Windows. Важно понимать разницу между тем, как структурируются текстовые файлы в Linux и в DOS/Windows.

В Linux каждая строка текстового файла оканчивается символом новой строки. Он представляется символьной константой 'n', ASCII-код которой равен 10. В Windows строки разделяются двухсимвольной комбинацией символ возврата каретки (константа 'r', ASCII-код 13), за которым идет символ новой строки.

Некоторые текстовые редакторы Linux при отображении текстовых файлов Windows ставят в конце каждой строки обозначение ^M — символ возврата каретки. В Emacs такие файлы отображаются правильно, но в строке режима появляется запись (DOS). Многие Windows-редакторы, например Notepad (Блокнот), показывают содержимое текстовых файлов Linux в виде одной длинной строки, так как предполагают наличие в конце строки символа возврата каретки.

Если программа читает текстовые файлы, сгенерированные Windows-программами, желательно менять последовательность 'rn' одним символом новой строки. Точно так же при записи текстовых файлов, которые будут читаться Windows-программами, нужно менять одиночные символы новой строки комбинациями 'rn'.

В листинге Б.4 демонстрируется применение функции read(). Программа отображает шестнадцатиричный дамп файла, заданного в командной строке. В каждой строке показано смещение от начала файла, а затем — следующие 16 байтов.

Листинг Б.4. (hexdump.c) Отображение шестнадцатеричного дампа файла

#include <fcntl.h>

#include <stdio.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>


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

 unsigned char buffer[16];

 size_t offset = 0;

 size_t bytes_read;

 int i;


 /* Открытие файла для чтения. */

 int fd = open(argv[1], O_RDONLY);


 /* Чтение данных из файла по одному блоку за раз. Чтение

    продолжается до тех пор, пока размер очередной порции байтов

    не окажется меньше размера буфера. Это свидетельствует

    о достижении конца буфера. */

 do {

  /* чтение следующей строки байтов. */

  bytes_read = read(fd, buffer, sizeof(buffer));

  /* Отображение смещения, а затем самих байтов. */

  printf("0x%06x : ", offset);

  for (i = 0; i < bytes_read; ++i)

   printf("%02x ", buffer[i]);

  printf("n");

  /* Вычисление позиции в файле. */

  offset += bytes_read;

 }

 while (bytes_read == sizeof(buffer));


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

 close(fd);

 return 0;

}

Ниже показаны результаты работы программы. Она выводит дамп самой себя.

% ./hexdump hexdump

0x000000 : 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

0x000010 : 02 00 03 00 01 00 00 00 c0 B3 04 0B 34 00 00 00

0x000020 : e8 23 00 00 00 00 00 00 34 00 20 00 06 00 28 00

0x000030 : 1d 00 1a 00 06 00 00 00 34 00 00 00 34 80 04 08

...

Эти результаты могут быть разными в зависимости от того, какой компилятор применялся и какие флаги компиляции были установлены.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*