【问题标题】:Using getline vs fgets for basic file printing使用 getline 与 fgets 进行基本文件打印
【发布时间】:2019-09-06 02:21:08
【问题描述】:

我正在使用以下内容来打印文件的行:

int main() {

    FILE *fptr = fopen("test20k.csv", "r");
    char buffer[MAXLINE];

    while (fgets(buffer, sizeof(buffer), fptr) != NULL)
        printf("%s", buffer);
    putchar('\n');

    return 0;

}

如何使用getline 完成相同的操作?这是一个更概念化的类似问题:getline() vs. fgets(): Control memory allocation

【问题讨论】:

    标签: c posix fgets getline


    【解决方案1】:

    您只需检查getline(3) - Linux manual page 即可确定要传递的适当参数类型和要处理的返回类型以及getline 如何指示成功/失败。

    那么,只需在您的代码中将fgets() 替换为getline()。所有面向行的 输入函数都读取并包含尾随'\n',因此这里没有变化。但是,请注意getline() 为您的buffer 分配存储空间,因此您在完成后需要free()buffer - 要求除了stdio.h 之外还包括stdlib.h

    此外,您注意到getline 不是标准 C 库的一部分。相反,getline 是一个 POSIX 函数,因此并非每个 C 实现都需要提供它,因此您可能会遇到可移植性问题。

    基本上就是这样。不过,在您的代码中,您不应该使用硬编码文件名。这就是main() 接受参数的原因之一。因此,只需将要读取的文件名作为第一个参数传递给程序(如果没有提供参数,您也可以默认从stdin 读取)

    将它们放在一起,作为最低限度的实现,您可以这样做:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main (int argc, char **argv) {
    
        size_t n = 0;           /* initial alloc size, 0 - getline decides */
        char *buffer = NULL;    /* pointer to block of mem holding input */
        /* use filename provided as 1st argument (stdin by default) */
        FILE *fptr = argc > 1 ? fopen (argv[1], "r") : stdin;
    
        if (!fptr) {    /* validate file open for reading */
            perror ("file open failed");
            return 1;
        }
    
        /* you pass the address of your buffer and a pointer to n */
        while (getline (&buffer, &n, fptr) != -1)
            printf("%s", buffer);
        putchar('\n');
    
        if (fptr != stdin)   /* close file if not stdin */
            fclose (fptr);
    
        free (buffer);      /* getline allocates, don't forget to free */
    
        return 0;
    }
    

    检查一下,如果您还有其他问题,请告诉我。

    输入文件示例

    $ cat dat/captnjack.txt
    This is a tale
    Of Captain Jack Sparrow
    A Pirate So Brave
    On the Seven Seas.
    

    使用/输出示例

    $ ./bin/getline_file dat/captnjack.txt
    This is a tale
    Of Captain Jack Sparrow
    A Pirate So Brave
    On the Seven Seas.
    

    【讨论】:

      【解决方案2】:

      fgets()/getline() 常用于阅读文本

      不常见的是,输入流包含一个空字符 '\0'

      fgets() 像任何字符一样读取 空字符。它不会停止读取输入的

      以下内容仅打印到 string 中遇到的第一个 null 字符 - 它与读取的 null 字符 和附加的字符没有区别fgets() 添加的空字符

      while (fgets(buffer, sizeof(buffer), fptr)) {
        printf("%s", buffer);  // Maybe stops too early?
      }
      

      getline(),虽然是非标准的 C,但有一个优势,因为它返回读取的字符数。然后打印可以打印到返回的计数,而不仅仅是第一个空字符

      size_t n = 0;
      char *buffer = NULL;
      
      ssize_t sz;
      while ((sz = getline (&buffer, &n, fptr)) != -1) {
        fwrite(buffer, 1, sz, stdout);
      }
      
      free(buffer);
      

      注意:size_t n = 0; char *buffer = NULL; 是初始设置。 getline (&amp;buffer, &amp;n, ...) 接收这两个变量的地址,允许它根据需要更新这两个变量(由于重新分配)。最大缓冲区大小为SIZE_MAX 或内存池的限制。我们不需要知道它在 getline() 中是如何工作的,因为这是一个不同的实现细节。


      虽然空字符在简单的文本文件中并不常见,但我发现编写代码最好be prepared 处理空字符。他们很容易想到读取一个UTF16 编码的文本文件。当然,期待 ASCII 或 UTF8 文本文件并获得 UTF16 文件是一个问题,很好地打印思想 null 字符 有助于识别问题。

      【讨论】:

      • 感谢您的回答。一个问题——为什么将*buffer 设置为NULL?为什么也是 &n = 0。如果一切都设置为零,您可以使用的最大缓冲区大小是多少,或者它是如何工作的?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-21
      • 1970-01-01
      • 2019-09-22
      相关资源
      最近更新 更多