I want the same functionality of readline but for a file. I don't want to pass开发者_运维知识库 a buffer and size. I'd like a method to malloc the right amount of space
With fgetc
, you can read a character at a time from a file.
Thus, you can create a function that reads a file line by line by calling fgetc
several times. If a line is over, fgetc
reads a \n
. If the file is over, it reads EOF
.
Now, you do the following: You create a char line[1024]
(resp. a char*
that is created via malloc
) (or any other size) at the beginning, and fill it either one of the following is the case:
fgetc
gets\n
: This means, that the current line is over, and you are done with this line.fgetc
getsEOF
: This means, that the whole file is over and you are completely done.fgetc
gets anything else and there is still space available inline
: Then you simply copy the char read into the appropriate position inline
.fgetc
gets anything else andline
is already completely filled: Then, yourealloc
new memory forline
and grow the currentline
(to be more specific, it is practical to double the size ofline
in this step).
So basically you need to inform yourself about fgetc
and realloc
and combine these two functions (and some auxiliary functions) to get what you want.
Here's a solution I've used before. It will read a line from a text file up to and including the newline. It reads into a local, fixed-sized buffer first, and then appends that buffer to the result.
Reading ends when we see a newline or EOF or hit an error on input.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define PAGE_SIZE ... // some size large enough to handle most cases
char *getLine(FILE *stream)
{
char *res = NULL;
char inbuf[PAGE_SIZE];
size_t len = 0;
/**
* We want to use strcpy the first time through the loop,
* then strcat afterward. Using a function pointer means
* we don't have to execute a test each time through the
* loop. For a sane text file where individual lines aren't
* more than a few dozen characters long, this really doesn't
* buy us anything over an if-else statement; I just think it's a cool trick.
*
* For C99, the prototype should be
*
* char *(*f)(char * restrict, const char * restrict)
*/
char *(*f)(char *, const char *) = strcpy;
while (fgets(inbuf, sizeof inbuf, stream))
{
char *tmp = realloc(res, len + strlen(inbuf) + 1);
if (tmp)
{
res = tmp;
f(res, inbuf);
f = strcat;
len += strlen(inbuf) + 1;
}
if (strchr(inbuf, '\n'))
break;
}
if (feof(stream))
// hit EOF
else
// error on read; how you deal with it is up to you.
return res;
}
Note that if we hit EOF or error on the initial read, the function will return NULL
.
You will need to free
each line when you're done with it.
精彩评论