Как читать построчно после того, как я прочитал текст в буфер?

Сначала я читаю текст в буфер, вызывая 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 - хороший способ. Я просто хочу знать, может ли этот метод сделать то же самое.


person Fei Xue    schedule 12.05.2012    source источник
comment
Почему бы не использовать fgets() для чтения файла по одной строке за раз?   -  person Adam Liss    schedule 12.05.2012
comment
Или getline(), если вы используете систему, совместимую с POSIX.   -  person Jack    schedule 12.05.2012


Ответы (4)


Попробуй это:

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");
}
person Jack    schedule 12.05.2012
comment
@AdamLiss: это зависит. Видите, здесь есть два вопроса. Одна может быть решена только с помощью fgets(), а другая может быть решена с помощью fgets() или getline(). - person Jack; 12.05.2012
comment
и fgets, и getline нуждаются в файловом указателе, поэтому нет необходимости вызывать fread. я хочу читать построчно из буфера, как? - person Fei Xue; 12.05.2012
comment
@ccsnailpp: что-то вроде второго примера кода? или хотите прочитать это из переменной? - person Jack; 12.05.2012
comment
@ Джек, я хочу прочитать это из переменной, а не из указателя файла - person Fei Xue; 12.05.2012

Вы можете найти расположение символа конца строки, используя strchr() следующим образом :

char *eol = strchr(line, '\n');

Все, что до *eol, является первой строкой. Затем перейдите от line к eol + 1, удалите все последующие символы \r или \n и повторяйте процесс, пока strchr() не вернет NULL, чтобы указать, что больше нет символов новой строки. В этот момент переместите все оставшиеся данные в начало буфера и прочитайте следующий фрагмент из файла.

Если вы беспокоитесь об эффективности, вы можете избежать перемещения данных, используя 2 буфера и чередуя их, но даже наивный метод, вероятно, быстрее, чем fgets(), если в файле много строк.

person Adam Liss    schedule 12.05.2012
comment
лучшая и самая простая версия на данный момент! - person br1; 21.11.2017

как насчет strtok

char *line;
line = strtok(texbuf, '\n');
person Musa    schedule 12.05.2012
comment
Будьте очень осторожны, используя strtok(). Он не реентерабельный и изменяет свой ввод по мере его обработки. - person Adam Liss; 12.05.2012
comment
@nos да, я уже знал это, так что это просто попытка. альтернативный метод. Я думаю, что fgets самый простой. - person Fei Xue; 12.05.2012

Вы сказали: «Я знаю, что использование fgets — хороший способ. Я просто хочу знать, может ли этот метод делать то же самое». Конечно, вы можете, вы просто повторно реализуете fgets, как в библиотеке c. Библиотека 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);
}
person pizza    schedule 12.05.2012
comment
это почти то, что я хочу. Я почти забыл, что fgets — это библиотечная функция, а не системный вызов. - person Fei Xue; 12.05.2012