【问题标题】:How do I read a file line by line in C from the terminal?如何从终端逐行读取 C 中的文件?
【发布时间】:2018-01-24 02:26:00
【问题描述】:

我已经读到我可以使用 fopen 逐行读取文件,但我想从终端访问该文件。 这是我尝试过的:

$ ./myprogram < input.txt > output.txt

我不确定是否可以使用 scanf 或其他方式来做到这一点?

【问题讨论】:

  • 读取input.txt' line by line and use fprintf` 写入`output.txt'。
  • 这个问题的问法远不那么广泛“为我写代码”many, many, times。我建议阅读其中一些以获得灵感。
  • 简短答案是#define BUFSZ 1024 ... char buf[BUFSZ] = ""; while (fgets (buf, BUFSZ, stdin)) fputs (buf, stdout);

标签: c terminal scanf fopen


【解决方案1】:

在这里,如果您考虑一下自己在做什么,您只是不断地从stdin 读取并将相同的字节写入stdout,直到您收到EOF。虽然您可以使用面向字符的方法(例如 getchar),但使用固定长度缓冲区的读取将大大减少您的读写次数。

只需声明一个大小合适的缓冲区1024(或使用提供的默认BUFSIZ,通常在Linux 上使用8192,在windoze 上使用512)。然后反复调用fgets,一次读取一个缓冲区的字符,然后用fputs将它们写回stdout。就是这么简单。

#include <stdio.h>

#define BUFSZ 1024

int main (void) {

    char buf[BUFSZ] = "";

    while (fgets (buf, BUFSZ, stdin))
        fputs (buf, stdout);

    return 0;
}

理想情况下,您会希望缓冲区大小比最长的行长,尽管它的大小实际上并不重要。您可以一次阅读每一行,也可以多次调用fgets。唯一的区别是函数调用的数量。

【讨论】:

    【解决方案2】:
        #include <stdio.h>
    
        #define BUFSIZE 1024
    
        int main(int argc, char *argv[])    
        {
            char *line = (char *)malloc(BUFSIZE);
            if (!line)
            {
                printf("malloc buffer failed...\n");
                return 1;
            }
            memset(line, 0, sizeof(line));
            FILE *fp;
            FILE *writefp;
            int c;
            int count = 0;
            int count_buf = BUFSIZE;
            char scanf_answer;
    
            if (argc != 3)
            {
                printf("./myprogram <input.txt> output.txt\n");
                return 1;
            }
            fp = fopen(argv[1], "r");
    
            for (;;)
            {
                c = getc(fp);
                if (c == '\n')
                {
                    printf("%s\n", line);
                    printf("<Did you want to write this line to [%s]?>", argv[2]);
                    scanf("%c", &scanf_answer);
                    if (scanf_answer == 'Y' || scanf_answer == 'y')
                    {
                        writefp = fopen(argv[2], "a+");
                        fprintf(writefp, "%s\n", line);
                        fclose(writefp);
                    }
                    memset(line, 0, sizeof(line));
                }
                else if (c == EOF)
                {
                    printf("%s\n", line);
                    printf("<Did you want to write this line to [%s]?>", argv[2]);
                    scanf("%c", &scanf_answer);
                    if (scanf_answer == 'Y' || scanf_answer == 'y')
                    {
                        writefp = fopen(argv[2], "a+");
                        fprintf(writefp, "%s\n", line);
                        fclose(writefp);
                    }
                    printf("End of file\n");
                    break;
                }
                if (count >= count_buf)
                {
                    line = realloc(line, BUFSIZE);
                    count_buf += BUFSIZE;
                    if (!line)
                    {
                       printf("realloc buffer failed...\s");
                       return 1;
                    }
                    count = 0;
                }
                sprintf(line,"%c%c", line, c);
                ++count;
            }
            fclose(fp);
            return 0;
        }
    

    此代码将打印每一行,您决定将每一行写入 output.txt,并在文件末尾打印End of file

    【讨论】:

    • 您需要查看此代码。您的 sprint 尝试用每个字符覆盖 line[0]。但是,c 没有定义,但您将其视为int(正确)或char(错误);它不是字符串,所以%s 格式错误。
    • 如果你修复了这些机制,你没有采取任何步骤来处理行,也没有防止你的line缓冲区溢出。文件通常是兆字节,如果不是千兆字节,或者更大。
    • @JonathanLeffler 对不起我的代码,我只是写了一些sn-ps的代码来提醒作者问题,忘记了一些基本的语法定义,谢谢你的提醒
    • 好多了——但是……记住getchar()返回一个int,而不是char,所以你需要int c;。您仍然不能使用sprintf(line, "%s", c),因为c 不是指向空终止字符串的指针。你可以使用%c。然后,您需要确保每次都写入一个新位置——您仍然在每次迭代中覆盖line[0]。此外,您将换行符复制到每行的开头 — 或者如果 sprintf() 工作正常,则将其复制。
    • @JonathanLeffler 是的,我改了代码,谢谢你的教导
    【解决方案3】:

    $ ./myprogram &lt; input.txt &gt; output.txt

    您发布的命令使用称为 IO 重定向的 shell 功能在标准输入上从一个文件生成输入,并将输出重定向到标准输出到另一个文件。

    如果您可以使用 POSIX getline(),即使对于任意长度的行,将行作为程序的输入也非常容易。有关详细信息,请参阅手册页(链接如下)。

    这是一个例子:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        // this is the buffer data is read to (including trailing newline)
        char *buffer = 0;
        // this will be set to the size of the buffer
        size_t buffer_size = 0;
        // this will be set to the number of bytes read
        ssize_t bytes_read;
        while ((bytes_read = getline(&buffer, &buffer_size, stdin)) != -1) {
            // do something with line
            printf("%s", buffer);
            // the same buffer will be reused in the next loop iteration
        }
        // free buffer eventually
        free(buffer);
        return 0;
    }
    

    可能的输出:

    $ gcc test.c && ./a.out < test.c
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
    [...]
    

    请注意,scanf() 用于获取格式化输入,而不是读取行。我建议您在此处了解更多关于 IO(在流上)的不同方法:

    供参考:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-21
      • 2012-06-13
      • 1970-01-01
      • 2022-01-25
      • 2020-01-16
      相关资源
      最近更新 更多