Чтение файлов с помощью API POSIX

рассмотрим следующий фрагмент кода для чтения содержимого файла в буфер

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BLOCK_SIZE 4096

int main()
{
   int fd=-1;
   ssize_t bytes_read=-1;
   int i=0;
   char buff[50];
   //Arbitary size for the buffer?? How to optimise.
   //Dynamic allocation is a choice but what is the
   //right way to relate the file size to bufffer size.

   fd=open("./file-to-buff.txt",O_RDONLY);
   if(-1 == fd)
   {
      perror("Open Failed");
      return 1;
   }

   while((bytes_read=read(fd,buff,BLOCK_SIZE))>0)
   {
      printf("bytes_read=%dn",bytes_read);
   }

   //Test to characters read from the file to buffer.The file contains "Hello"
   while(buff[i]!='')
   {
      printf("buff[%d]=%dn",i,buff[i]);
      i++;
      //buff[5]=n-How?
   }
   //buff[6]=``-How?
   close(fd);
   return 0;
}

Описание Код:

  • входной файл содержит строку "Hello"
  • этот контент должен быть скопирован в буфер.
  • цель достигнута open и read API POSIX.
  • API чтения использует указатель на буфер*размер arbitary* для копирования данных в.

вопросы:

  • динамическое распределение-это метод, который должен использоваться для оптимизации размера буфера.Какова правильная процедура связывания / получения размера буфера из размера входного файла?
  • я вижу в конце read операция чтение скопировало new line character и NULL символ, кроме символов "Привет". Пожалуйста, подробнее об этом поведении читать.

Пример Вывода

bytes_read=6

buff[0]=H

buff[1]=e

buff[2]=l

buff[3]=l

buff[4]=o

buff[5]=

PS: Input file-созданный пользователем файл, не созданный программой (с помощью write API-интерфейс). Просто упомянуть здесь, в случае, если это делает разница.

4 ответов


поскольку вы хотите прочитать весь файл, лучший способ-сделать буфер таким же большим, как размер файла. Нет смысла изменять размер буфера. Это просто вредит производительности без уважительной причины.

вы можете получить размер файла несколькими способами. Быстрый-и-грязный способ-это lseek() до конца файл:

// Get size.
off_t size = lseek(fd, 0, SEEK_END); // You should check for an error return in real code
// Seek back to the beginning.
lseek(fd, 0, SEEK_SET);
// Allocate enough to hold the whole contents plus a '' char.
char *buff = malloc(size + 1);

другой способ получить информацию с помощью fstat():

struct stat fileStat;
fstat(fd, &fileStat); // Don't forget to check for an error return in real code
// Allocate enough to hold the whole contents plus a '' char.
char *buff = malloc(fileStat.st_size + 1);

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

#include <sys/stat.h> // For fstat()
#include <unistd.h>   // For lseek()

отметим, что read() не завершает автоматически данные с . Вам нужно сделать это вручную, поэтому мы выделяем дополнительный символ (размер+1) для буфера. Причина, по которой уже есть характер там в вашем случае-чистый случайный шанс.

конечно, с buf теперь динамически выделенный массив, не забудьте освободить его снова, когда он вам не нужен больше:

free(buff);

имейте в виду, что выделение буфера размером с файл, который вы хотите прочитать, может быть опасным. Представьте, что (по ошибке или намеренно, не имеет значения) файл имеет несколько ГБ. Для таких случаев хорошо иметь максимально допустимый размер на месте. Однако, если вы не хотите таких ограничений, вам следует переключиться на другой метод чтения из файлов:mmap(). С mmap(), вы можете сопоставить части файла в память. Таким образом, это не имеет значения, насколько велик файл, так как вы можете работать только с его частями одновременно, контролируя использование памяти.


1, Вы можете получить размер файла со статом (filename, & stat), но определить буфер до размера страницы просто отлично

2, Во-первых, нет нулевого символа после "Hello", должно быть, случайно, что область стека, которую вы выделили, была 0 до выполнения вашего кода, см. главу 7.6 APUE. Фактически вы должны инициализировать локальную переменную перед ее использованием.

Я попытался создать текстовый файл с помощью vim, emacs и echo-n Hello > file-to-buff.txt, только vim добавляет строку перерыв автоматически


вы можете рассмотреть возможность динамического выделения буфера, сначала создав буфер фиксированного размера с помощью malloc и удвоение (с realloc) размер, когда вы заполните его. Это будет иметь хорошую временную сложность и космический компромисс.

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

код вы питания выделяет 50 байт для буфера, но вы передаете 4096 как размер read. Это может привести к переполнению буфера файлы более размером 50 байт.

Что касается' \n 'и'\0'. Новая строка, вероятно, находится в файле, а "\0 " уже был в буфере. Буфер выделяется в стеке в вашем коде, и если этот раздел стека еще не использовался, он, вероятно, будет содержать нули, помещенные туда операционной системой, когда ваша программа была нагруженный.

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

несколько других пунктов, которые больше вопрос стиля:

  • вы можете рассмотреть возможность использования for (i = 0; buff[i]; ++i) вместо цикла while для печати в конце. Таким образом, если кто-то возится с переменной индекса i вы будете незатронутый.
  • вы можете закрыть файл раньше, после завершения чтения из него, чтобы избежать открытия файла в течение длительного периода времени (и, возможно, забыть закрыть его, если произойдет какая-то ошибка).

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

в C конец строки представлен этим карактером. Если read набор 4 символов printf прочитает эти 4 символа и проверит 5-й: если это не '', он будет продолжать печатать до следующего ''. Это также источник буфера переполнение

на '\n', вероятно, он находится во входном файле.