【问题标题】:Reading a file from stdin从标准输入读取文件
【发布时间】:2016-09-22 10:49:33
【问题描述】:

自从我用 C 编程以来已经有好几年了,所以我一直在努力做一个简单的“从标准输入获取文件名和路径,读取文件,将文件打印到标准输出”任务,我知道不应该这样做要那么难,但你。这是我的代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void) {
    int c;
    FILE *file;
    //scanf("%s", filename);
    char *filename;
    filename = (char *)malloc(200 * sizeof(char));

    read(STDIN_FILENO, filename, 200);


    printf("%s", filename);

    file = fopen(filename, "r");

    if (file) {
        while ((c = getc(file)) != EOF)
            putchar(c);
        fclose(file);
    } else {
        printf("File not found.");
    }
    printf("\n");

    return(0);
}

我的代码继续简单地打印出File not found.,当我知道我的文件路径和一切都是正确的时(不仅因为我真的将它从我的文件夹中的 Mac OSX El Capitan 拖放到终端中 -多么可爱的功能,而且)因为我有一个使用scanf 的程序的不同版本,它找到了文件并很好地阅读了它,(如你所见,我在我的代码中注释掉了它)。

我正在编写的另一个程序只使用了这个程序,我去掉了scanf,因为我认为它对该程序中的其他事情产生了负面影响,所以我希望能够使用read()

如果有人对我如何解决这个问题或为什么这不起作用有任何建议,我将不胜感激,因为我已经在这工作了几个小时,并且非常想继续我的 我需要编码的实际程序!

非常感谢

【问题讨论】:

  • 你不应该转换malloc()的返回值,c不需要它。不要使用sizeof(char),因为它什么都不添加,并且始终为 1,不要使用malloc(),因为您可以定义一个包含 200 个字符的数组,还可以使用fgets() 读取文件名并删除结束行字符。
  • 在调用malloc()read()等系统函数时,一定要检查返回值以保证操作成功。显示错误消息时,这些错误指示是从对系统函数的调用中返回的,在 stderr 上显示错误,以及您的文本和系统错误消息,使用:perror( "your text" );
  • 在现代C中,当从main()函数返回时,如果返回值为0则不需要return语句..

标签: c file stdin c-strings


【解决方案1】:

您必须删除正在读取并存储到 filename 缓冲区中的 '\n' 换行符。

其中一个是包含string.h 并在读取文件名后

char *newline = strchr(filename, '\n');
if (newline != NULL)
    *newline = '\0';

另外,使用fgets() 而不是read(),因为这样程序更便携。更重要的是,read() 不会添加 null 终止符,这对于将缓冲区用作字符串非常重要——例如将其传递给fopen()——正确。如果你想使用 read 试试这样的

ssize_t length;
char filename[200];
length = read(STDIN_FILENO, filename, sizeof(filename) - 1);
if (length <= 0)
    return -1; // No input or input error
if (filename[length] == '\n')
    filename[--length] = '\0';
else
    filename[length] = '\0';

否则,试试这个更简单的

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <string.h>

int main(void) 
{
    FILE *file;
    char filename[200];
    char *newline;   

    if (fgets(filename, sizeof(filename), stdin) == NULL)
        return -1; // Input error / EOF
    newline = strchr(filename, '\n');
    if (newline) // ? is a newline present?
        *newline = '\0';
    printf("**%s**\n", filename); // ** will help checking for
                                  //    the presence of white spaces.

    file = fopen(filename, "r");
    if (file) {
        int chr;
        while ((chr = fgetc(file)) != EOF)
            fputc(chr, stdout);
        fclose(file);
    } else {
        printf("File not found.");
    }
    printf("\n");

    return 0;
}

【讨论】:

  • 如果你想使用read,你需要使用calloc而不是malloc。或在读取的字符数中添加一个空终止符。
  • @BLUEPIXY 没办法!但我确实忘记提及...不calloc() 因为正是在这种情况下它会隐藏一个错误。它会不必要地将所有字节初始化为0
  • 请注意,使用 read()fgets() 有优势,它告诉您读取了多少字节(如 getline() 所做的,与 fgets() 不同),因此您可以检查可能通过索引而不是搜索来换行。有一种极端情况,您在程序开始之前已经设法输入了几行输入(或者您从常规文件重定向了标准输入);那么你的长 read() 可能包含几个换行符。