C читать файл построчно - PullRequest
       101

C читать файл построчно

154 голосов
/ 17 августа 2010

Я написал эту функцию для чтения строки из файла:

const char *readLine(FILE *file) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    const char *constLine = line;
    return constLine;
}

Функция правильно читает файл, и, используя printf, я вижу, что строка constLine также правильно прочитана.

Однако, если я использую функцию, например, так:

while (!feof(myFile)) {
    const char *line = readLine(myFile);
    printf("%s\n", line);
}

printf выводит бессмысленно.Почему?

Ответы [ 15 ]

1 голос
/ 17 августа 2010

Вы должны использовать функции ANSI для чтения строки, например.fgets.После вызова вам нужно free () в контексте вызова, например:

...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...

const char *readLine(FILE *file)
{
  char *lineBuffer=calloc(1,1), line[128];

  if ( !file || !lineBuffer )
  {
    fprintf(stderr,"an ErrorNo 1: ...");
    exit(1);
  }

  for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
  {
    if( strchr(line,'\n') ) *strchr(line,'\n')=0;
    lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
    if( !lineBuffer )
    {
      fprintf(stderr,"an ErrorNo 2: ...");
      exit(2);
    }
  }
  return lineBuffer;
}
1 голос
/ 17 августа 2010
const char *readLine(FILE *file, char* line) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    return line;

}


char linebuffer[256];
while (!feof(myFile)) {
    const char *line = readLine(myFile, linebuffer);
    printf("%s\n", line);
}

обратите внимание, что переменная 'line' объявляется в вызывающей функции и затем передается, поэтому ваша функция readLine заполняет заранее определенный буфер и просто возвращает его.Именно так работает большинство библиотек C.

Есть и другие способы, о которых я знаю:

  • определение char line[] как статического (static char line[MAX_LINE_LENGTH] ->он будет держать это значение ПОСЛЕ возвращения из функции).-> плохо, функция не реентерабельна, и может возникнуть состояние гонки -> если вы вызовете ее дважды из двух потоков, она перезапишет свои результаты
  • malloc(), используя строку символов [] и освобождая еев вызове функций -> слишком много дорогих malloc с и делегировании ответственности за освобождение буфера другой функции (наиболее элегантное решение - вызвать malloc и free для любых буферов в той же функции)

кстати, «явное» приведение от char* к const char* избыточно.

btw2, нет необходимости malloc() lineBuffer, просто определите его char lineBuffer[128], поэтомувам не нужно его освобождать

btw3 не используйте «динамические стековые массивы» (определяя массив как char arrayName[some_nonconstant_variable]), если вы точно не знаете, что делаете, это работает только вC99.

0 голосов
/ 08 августа 2018

Мое орудие с нуля:

FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);

size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
    bytes_read = strlen(buf);
    // if line length larger than size of line buffer
    if (linesize + bytes_read > nbytes) {
        char *tmp = line;
        nbytes += nbytes / 2;
        line = (char *) malloc(nbytes);
        memcpy(line, tmp, linesize);
        free(tmp);
    }
    memcpy(line + linesize, buf, bytes_read);
    linesize += bytes_read;

    if (feof(pFile) || buf[bytes_read-1] == '\n') {
        handle_line(line);
        linesize = 0;
        memset(line, '\0', nbytes);
    }
}

free(buf);
free(line);
0 голосов
/ 25 сентября 2014

Мне нужен код с нуля 0, поэтому я сделал это, чтобы прочитать содержимое словарного словаря построчно.

char temp_str [20];// вы можете изменить размер буфера в соответствии с вашими требованиями и длиной одной строки в файле.

Примечание Я инициализировал буфер нулевым символом каждый раз, когда читаю строку.Функция может быть автоматизирована, но поскольку мне нужно подтверждение концепции и я хочу разработать программу Byte By Byte

#include<stdio.h>

int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
 i=0;
  char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
  temp_ch=fgetc(fp);
  temp_str[i]=temp_ch;
  i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}
0 голосов
/ 26 марта 2013

Вы делаете ошибку, возвращая указатель на автоматическую переменную. Строка переменной размещается в стеке и живет только до тех пор, пока функционирует функция. Вам не разрешено возвращать указатель на него, потому что как только он вернется, память будет отдана в другом месте.

const char* func x(){
    char line[100];
    return (const char*) line; //illegal
}

Чтобы избежать этого, вы либо возвращаете указатель на память, которая находится в куче, например. lineBuffer и это должно быть обязанностью пользователя вызывать free (), когда он закончил с этим. В качестве альтернативы вы можете попросить пользователя передать вам в качестве аргумента адрес памяти, на который нужно записать содержимое строки.

...