在c中逐行读取具有可变行长度的文件

时间:2010-06-21 18:02:19

标签: c file-io

在C中,有没有办法逐行读取文本文件而不知道要为它分配多少空间?

这是我的意思的一个例子:

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

感谢您的帮助!

7 个答案:

答案 0 :(得分:5)

没有什么是自动的。您需要继续增加缓冲区并调用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;
}

答案 1 :(得分:2)

如果你有glibc或其他支持POSIX(2008)的libc,你可以使用getline

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

getline()从中读取整行   流,存储的地址   包含文本的缓冲区   * lineptr。缓冲区以空值终止并包含   换行符,如果找到了。

     

如果* lineptr为NULL,则getline()   将分配一个缓冲区用于存储   这条线应该被释放   用户程序。 (* n中的值是   忽略)。

答案 2 :(得分:1)

基本上,您应该分配任意大小的临时缓冲区。然后你应该扫描输入换行符,用扫描字符填充缓冲区。如果缓冲区填满,则分配新的,更大的缓冲区,将旧内容复制到新缓冲区并释放旧缓冲区。

Glib库具有g_io_channel_read_line功能,可以为您完成此任务。

答案 3 :(得分:0)

不直接。

要解决这个问题,如果缓冲区不够大,你必须准备好处理fgets失败。从malloc line开始到一个合理的初始缓冲区(比方说256个字符),然后realloc每次fgets返回NULL时都是{{1}}的两倍。

答案 4 :(得分:0)

对于“动态线条大小”,只需使用您想要使用的最大内存。如果线路未完成,请处理您使用的部件,并执行一些其他操作,直到到达线路末端。使用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;
}

答案 5 :(得分:0)

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
}

答案 6 :(得分:0)

您可以将一行的行一次读入固定大小的缓冲区,然后将该固定大小的缓冲区的内容复制到动态分配和可调整大小的缓冲区中:

#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;
}