当我把文本读入缓冲区后,如何逐行阅读?

7

首先,我通过调用fread将文本读入缓冲区,然后我想逐行读取它,该如何做?我尝试使用sscanf,但似乎不起作用。

char textbuf[4096];
char line[256];
FILE *fp;
fp = fopen(argv[1],"r");
memset(textbuf, 0, 4096);
fread(textbuf, 1, 4096, fp);

我知道使用fgets方法是一种好的方式,我只是想知道这种方法能否完成同样的事情。


为什么不使用fgets()逐行读取文件呢? - Adam Liss
如果您的系统兼容POSIX,则使用getline() - Jack
4个回答

11

试试这个:

fgets(textbuf, sizeof(textbuf), fp);

要逐行读取文件内容,可以使用:fgets(line, 128, fp) 或者 getline(&line, &size, fp);

编辑

如果你想从一个变量中读取内容,请看一下strtok()函数:

char * line = strtok(strdup(buffer), "\n");
while(line) {
   printf("%s", line);
   line  = strtok(NULL, "\n");
}

@AdamLiss:这要看情况。这里有两个问题,一个可以仅使用fgets()解决,另一个则可以使用fgets()或getline()来解决。 - Jack
无论是fgets还是getline都需要文件指针,因此不需要调用fread。我想逐行从缓冲区读取,怎么做? - Fei Xue
@ccsnailpp:想要类似第二个代码示例的东西吗?还是想要从一个变量中读取它? - Jack
@Jack 我想从一个变量中读取它,而不是从文件指针中读取。 - Fei Xue

8

您可以使用strchr()函数来查找换行符的位置,示例如下:

char *eol = strchr(line, '\n');
*eol之前的所有内容是第一行。然后从lineeol+1,去除任何后续的\r\n字符,并重复该过程,直到strchr()返回NULL表示没有更多的换行符为止。此时,将任何剩余的数据移动到缓冲区的开头,并从文件中读取下一个块。
如果您关心效率,您可以使用2个缓冲区并在它们之间轮流使用,但即使是简单的方法在文件有很多行时也可能比fgets()更快。

到目前为止,这是最好且最简单的版本! - br1

2

那么关于strtok呢?

char *line;
line = strtok(texbuf, '\n');

使用 strtok() 时要非常小心。它不是可重入的,并且在处理过程中修改其输入。 - Adam Liss
@nos 是的,我已经知道了,所以这只是一种尝试。另一种方法。我认为 fgets 是最简单的。 - Fei Xue

0
你说:“我知道使用fgets是一种好方法。我只想知道这种方法是否可以做同样的事情。” 当然可以,你只需重新实现c库中的fgets函数。c库实际上并没有逐行读取,而是一次性读入一个大块数据,并在调用fgets时给出一行数据。
虽然不是最有效的方法,但这是你需要做的一种示例。
#include <stdio.h>
typedef struct my_state {
 unsigned char * buf;
 int offset;
 int buf_size;
 int left;
 FILE * file;
} my_state_t;
int takeone(my_state_t * state) {
 if ((state->left - state->offset)<=0) {
  if (feof(state->file)) return -1;
  state->left = fread(state->buf,1,state->buf_size,state->file);
  state->offset = 0;
  if (state->left == 0) return -1;
 }
 return state->buf[state->offset++];
}
int getaline(my_state_t * state, char * out, int size) {
 int c;
 c = takeone(state);
 if (c < 0) return 0;
 while (c >=0 && size > 1) {
  *out++ = c;
  --size;
  if (c == '\n') break;
  c = takeone(state);
 }
 *out=0;
 return 1;
}
int main(int argc, char ** argv){
 FILE *fp;
 char textbuf[4096];
 char line[256];
 my_state_t fs;
 fs.buf=textbuf;
 fs.offset=0;
 fs.buf_size=4096;
 fs.left=0;
 fp = (argc>1)? fopen(argv[1],"rb") : stdin;
 fs.file = fp;
 while (getaline(&fs,line,256)) {
  printf("-> %s", line);
 }
 fclose(fp);
}

那差不多是我想要的。我差点忘了 fgets 是一个库函数,而不是系统调用。 - Fei Xue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接