Чтение файла с переменной длиной строки построчно в c - PullRequest
4 голосов
/ 21 июня 2010

В C есть способ читать текстовый файл построчно, не зная, сколько места для него выделить?

Вот пример того, что я имею в виду:

fgets(line, <dynamic line size>, fileHandle);

Спасибо за помощь!

Ответы [ 7 ]

5 голосов
/ 21 июня 2010

Ничего автоматического.Вы должны продолжать увеличивать свой буфер и вызывать fgets, пока не получите символ новой строки или EOF.

// NOTE: not production ready as does not handle memory allocation failures
size_t alloced = 128;
char *p = malloc(alloced);
char *walk = p;
size_t to_read = alloced;

for (;;) {
    if (fgets(walk, to_read, fp) == NULL)
        break;

    if (walk[strlen(walk) - 1] == '\n')
        break;

    to_read = alloced;
    alloced *= 2;

    p = realloc(p, allocated);
    walk = p + to_read;
}
2 голосов
/ 21 июня 2010

Если у вас есть glibc или другой libc, который поддерживает POSIX (2008), вы можете использовать getline:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

getline () читает всю строку из потока, сохраняя адресбуфер, содержащий текст в * lineptr.Буфер завершается нулем и включает символ новой строки, если он был найден.

Если * lineptr равен NULL, то getline () выделит буфер для хранения строки, который должен быть освобожден пользовательской программой.,(Значение в * n игнорируется.)

1 голос
/ 21 июня 2010

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

В библиотеке Glib есть g_io_channel_read_line функция, которая сделает это за вас.

0 голосов
/ 22 июня 2010

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

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define SIZE ... // some reasonable size to handle most cases

int getNextLine(FILE *stream, char **line, size_t *lineLength)
{
  char inbuf[SIZE];
  int done = 0;
  int rval = 1; // success

  *lineLength = 0;

  /**
   * If *line is not NULL, it is assumed that it was allocated on a
   * previous call to getNextLine.  Free it and set to NULL.
   */
  if (*line != NULL)
  {
    free(*line);
    *line = NULL;
  }

  while(!done)
  {
    char *tmp;

    if (fgets(inbuf, sizeof inbuf, stream))
    {
      /**
       * Check for newline character.  If present, clear it and set the
       * done flag to true.
       */
      char *newline = strchr(inbuf, '\n');
      if (newline != NULL)
      {
        *newline = 0;
        done = 1;
      }

      /**
       * Extend the dynamic buffer by the length of the input string
       * and copy the input string to it. 
       */
      tmp = realloc(*line, *lineLength + strlen(inbuf) + 1);
      if (tmp)
      {
        *line = tmp;
        (*line)[*lineLength] = 0;      
        strcat(*line, inbuf);        
        *lineLength += strlen(inbuf) + 1;
      }
      else
      {
        printf("Error allocating or extending buffer\n");
        rval = 0;
        done = 1;
      }
    }
    else
    {
      if (feof(stream))
      {
        printf("At end-of-file\n");
        rval = EOF;
      }
      else
      {
        printf("Error during read\n");
        rval = 0;
      }
      done = 1;
    } 
  }
  return rval;
}

int main(void)
{
  char *line = NULL;     // line *MUST* be initialized to NULL
  size_t lineLength = 0;
  int status;

  for (;;)
  {
    int status = getNextLine(stdin, &line, &lineLength);
    if (status == 0 || status == EOF)
      break;

    printf("Read %lu characters in line: \"%s\"\n", 
      (unsigned long) lineLength, line);
  }
  return 0;
}
0 голосов
/ 21 июня 2010
char *myGetLine(FILE *pFile)
{
  //Allocation a chunk of memory.
  //Read a chunk from the file.
  //While not a full line then reallocate a bigger chunk of memory and get the next chunk from the file.
  //NOTE: No malloc()/realloc() error checking is done here.
  //NOTE: Each call allocates a chunk of memory that the user must free().

  const int bufIncrSize = 128;   //or whatever increment you like
  int bufSize = bufIncrSize;
  char *pLine = (char *)malloc(bufIncrSize);
  pLine[0] = '\0';  //make it an empty string

  //while not EOF
  while (fgets(&pLine[strlen(pLine)], bufIncrSize, pFile) != NULL) {
    // If we got the newline, then we have the whole line
    if (pLine[strlen(pLine) - 1] == '\n')
      break;

    //else get a bigger buffer and try again
    bufSize += bufIncrSize;
    pLine = (char *)realloc(pLine, bufSize);
  }

  return pLine;  //NOTE the user is responsible for freeing the line buffer
}
0 голосов
/ 21 июня 2010

Для вашего «динамического размера строки» просто используйте максимальный объем памяти, который вы хотите использовать. Если строка не завершена, обработайте часть, которую вы использовали, и выполняйте некоторые дополнительные операции, пока не достигнете конца строки. Используйте strlen, чтобы определить, прочитали ли вы всю строку.

void ProcessFile( FILE *fp )
{
    int len = 0;
    char lineBuf[ MAX_SIZE ];

    while( !feof(fp) )
    {
        do
        {
            if( fgets( lineBuf, MAX_SIZE, fp ) > 0 )
            {
                fputs( lineBuf, STDOUT );
                len = strlen( lineBuf );
            }
        } while( !feof(fp) && lineBuf[len-1] != '\n' );

        puts( "A line has been processed!" );
    }

    return;
}
0 голосов
/ 21 июня 2010

Не напрямую.

Чтобы решить эту проблему, вы должны быть готовы обработать ошибку fgets, если буфер недостаточно велик.Начните с malloc ing line до приемлемого начального буфера (скажем, 256 символов), затем realloc, чтобы удваивать этот размер каждый раз, когда fgets возвращает NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...