C语言 C 逐行读取文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3501338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:12:29  来源:igfitidea点击:

C read file line by line

cfile-iolinestd

提问by lron

I wrote this function to read a line from a file:

我编写了这个函数来从文件中读取一行:

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] = '
while (!feof(myFile)) {
    const char *line = readLine(myFile);
    printf("%s\n", line);
}
'; char line[count + 1]; strncpy(line, lineBuffer, (count + 1)); free(lineBuffer); const char *constLine = line; return constLine; }

The function reads the file correctly, and using printf I see that the constLine string did get read correctly as well.

该函数正确读取文件,并且使用 printf 我看到 constLine 字符串也被正确读取。

However, if I use the function e.g. like this:

但是,如果我使用该功能,例如:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Retrieved line of length %zu:\n", read);
        printf("%s", line);
    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}

printf outputs gibberish. Why?

printf 输出胡言乱语。为什么?

回答by mbaitoff

If your task is not to invent the line-by-line reading function, but just to read the file line-by-line, you may use a typical code snippet involving the getline()function (see the manual page here):

如果您的任务不是发明逐行读取功能,而只是逐行读取文件,您可以使用涉及该getline()功能的典型代码片段(请参阅此处的手册页):

FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength];

filePointer = fopen("file.txt", "r");

while(fgets(buffer, bufferLength, filePointer)) {
    printf("%s\n", buffer);
}

fclose(filePointer);

回答by Rob

    lineBuffer[count] = '
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
   You can't use the value of `line` again (though you can assign a new value
   to the `line` variable if you want). */
'; realloc(lineBuffer, count + 1); return lineBuffer; }

回答by Gilles 'SO- stop being evil'

In your readLinefunction, you return a pointer to the linearray (Strictly speaking, a pointer to its first character, but the difference is irrelevant here). Since it's an automatic variable (i.e., it's “on the stack”), the memory is reclaimed when the function returns. You see gibberish because printfhas put its own stuff on the stack.

在你的readLine函数中,你返回一个指向line数组的指针(严格来说,一个指向它的第一个字符的指针,但这里的区别无关紧要)。由于它是一个自动变量(即,它“在堆栈上”),当函数返回时内存会被回收。你看到胡言乱语,因为printf已经把它自己的东西放在了堆栈上。

You need to return a dynamically allocated buffer from the function. You already have one, it's lineBuffer; all you have to do is truncate it to the desired length.

您需要从函数返回一个动态分配的缓冲区。你已经有了一个,它是lineBuffer; 您所要做的就是将其截断为所需的长度。

//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");

//check if file exists
if (fh == NULL){
    printf("file does not exists %s", filename);
    return 0;
}


//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL)  {
    printf(line);
}
free(line);    // dont forget to free heap memory

ADDED(response to follow-up question in comment): readLinereturns a pointer to the characters that make up the line. This pointer is what you need to work with the contents of the line. It's also what you must pass to freewhen you've finished using the memory taken by these characters. Here's how you might use the readLinefunction:

添加(对评论中的后续问题的回应):readLine返回指向构成该行的字符的指针。这个指针是你处理行内容所需要的。free当您使用完这些字符占用的内存时,这也是您必须传递的内容。以下是您可以如何使用该readLine功能:

lineBuffer[count] = '
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '
lineBuffer[count] = '
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '
void readLine(FILE* file, char* line, int limit)
{
    int i;
    int read;

    read = fread(line, sizeof(char), limit, file);
    line[read] = '
char * readline(FILE *fp, char *buffer)
{
    int ch;
    int i = 0;
    size_t buff_len = 0;

    buffer = malloc(buff_len + 1);
    if (!buffer) return NULL;  // Out of memory

    while ((ch = fgetc(fp)) != '\n' && ch != EOF)
    {
        buff_len++;
        void *tmp = realloc(buffer, buff_len + 1);
        if (tmp == NULL)
        {
            free(buffer);
            return NULL; // Out of memory
        }
        buffer = tmp;

        buffer[i] = (char) ch;
        i++;
    }
    buffer[i] = '
#include <stdio.h>
#include <stdlib.h>

void testGetFile() {
    // open file
    FILE *fp = fopen("input1.txt", "r");
    size_t len = 255;
    // need malloc memory for line, if not, segmentation fault error will occurred.
    char *line = malloc(sizeof(char) * len);
    // check if file exist (and you can open it) or not
    if (fp == NULL) {
        printf("can open file input1.txt!");
        return;
    }
    while(fgets(line, len, fp) != NULL) {
        printf("%s\n", line);
    }
    free(line);
}
'; // Detect end if (ch == EOF && (i == 0 || ferror(fp))) { free(buffer); return NULL; } return buffer; } void lineByline(FILE * file){ char *s; while ((s = readline(file, 0)) != NULL) { puts(s); free(s); printf("\n"); } } int main() { char *fileName = "input-1.txt"; FILE* file = fopen(fileName, "r"); lineByline(file); return 0; }
'; for(i = 0; i <= read;i++) { if('##代码##' == line[i] || '\n' == line[i] || '\r' == line[i]) { line[i] = '##代码##'; break; } } if(i != read) { fseek(file, i - read + 1, SEEK_CUR); } }
';
';
';
';

回答by RevoLab

##代码##

回答by qrdl

readLine()returns pointer to local variable, which causes undefined behaviour.

readLine()返回指向局部变量的指针,这会导致未定义的行为。

To get around you can:

要四处走动,您可以:

  1. Create variable in caller function and pass its address to readLine()
  2. Allocate memory for lineusing malloc()- in this case linewill be persistent
  3. Use global variable, although it is generally a bad practice
  1. 在调用函数中创建变量并将其地址传递给 readLine()
  2. 分配内存以供line使用malloc()- 在这种情况下line将是持久的
  3. 使用全局变量,尽管这通常是一种不好的做法

回答by Raku Escape

Use fgets()to read a line from a file handle.

用于fgets()从文件句柄中读取一行。

回答by JeremyP

Some things wrong with the example:

这个例子有一些错误:

  • you forgot to add \n to your printfs. Also error messages should go to stderr i.e. fprintf(stderr, ....
  • (not a biggy but) consider using fgetc()rather than getc(). getc()is a macro, fgetc()is a proper function
  • getc()returns an intso chshould be declared as an int. This is important since the comparison with EOFwill be handled correctly. Some 8 bit character sets use 0xFFas a valid character (ISO-LATIN-1 would be an example) and EOFwhich is -1, will be 0xFFif assigned to a char.
  • There is a potential buffer overflow at the line

    ##代码##

    If the line is exactly 128 characters long, countis 128 at the point that gets executed.

  • As others have pointed out, lineis a locally declared array. You can't return a pointer to it.

  • strncpy(count + 1)will copy at most count + 1characters but will terminate if it hits '\0'Because you set lineBuffer[count]to '\0'you know it will never get to count + 1. However, if it did, it would not put a terminating '\0'on, so you need to do it. You often see something like the following:

    ##代码##
  • if you malloc()a line to return (in place of your local chararray), your return type should be char*- drop the const.

  • 您忘记将 \n 添加到您的 printfs 中。错误消息也应该转到 stderr 即fprintf(stderr, ....
  • (不是很大,但是)考虑使用fgetc()而不是getc(). getc()是一个宏,fgetc()是一个适当的功能
  • getc()返回一个intsoch应该被声明为一个int。这很重要,因为与 的比较EOF将被正确处理。一些8位字符集使用0xFF作为有效字符(ISO-LATIN-1将是一个例子),并EOF它是-1,将0xFF如果分配给一个char
  • 该行存在潜在的缓冲区溢出

    ##代码##

    如果该行的长度正好是 128 个字符,count则在执行时为 128。

  • 正如其他人指出的那样,line是一个本地声明的数组。你不能返回指向它的指针。

  • strncpy(count + 1)最多将复制count + 1字符,但如果命中则会终止'\0'因为您设置lineBuffer[count]'\0'您知道它永远不会到达count + 1. 但是,如果这样做,则不会终止'\0',因此您需要这样做。您经常会看到类似以下内容:

    ##代码##
  • 如果您malloc()要返回一行(代替您的本地char数组),您的返回类型应该是char*- 删除const.

回答by Taner Mansur

##代码##

what about this one?

这个如何?

回答by Sam

Here is my several hours... Reading whole file line by line.

这是我的几个小时......逐行读取整个文件。

##代码##

回答by Nhat Dinh

Implement method to read, and get content from a file (input1.txt)

实现方法从文件中读取和获取内容(input1.txt)

##代码##

Hope this help. Happy coding!

希望这有帮助。快乐编码!