C 低级标准输入以接受文件名,然后将文件内容打印到标准输出

Posted

技术标签:

【中文标题】C 低级标准输入以接受文件名,然后将文件内容打印到标准输出【英文标题】:C low-level standard-in to accept filename then printing file contents to stdout 【发布时间】:2013-11-11 22:05:32 【问题描述】:

我想通过标准输入从用户那里获取文件名,用 open() 打开文件并将其分配给文件描述符,然后将该文件的内容打印到标准输出。这是我的代码,它不能正常工作。

问题:

    printf("输入文件名");声明永远不会出现 它从不打开文件;而是将用户输入的任何内容打印到屏幕上,然后打印“没有这样的文件或目录”错误消息并退出程序 程序存在后,我看到在终端提示之前打印“输入文件名”

代码:

    
        printf("Enter the filename: ");
        read(STDIN_FILENO, userInput, sizeof(userInput));
        if((input_file1 = open(userInput, O_RDONLY)) < 0)
        
            perror(userInput);
            exit(1);
        

        while((n = read(input_file1, buffer, sizeof(buffer))) > 0)
        
            if((write(STDOUT_FILENO, buffer, n)) < 0)
            
                perror("failed to write to standard-out");
                close(input_file1);
                exit(1);
            
        
    

控制台:

machineuser1168: ls // to show that the file exists
a.out  backup  file1 
machineuser1170: ./a.out
file1 // this is user input
file1 // this is printed for no reason
: No such file or directory // ????
Enter the filename: machineuser1171: // now the prompt is printed...? 

【问题讨论】:

不要混合FILE*函数(包括printf(),它与fprintf(stdout,...)same打开文件上的文件描述符函数相同。第一个被缓冲,第二个绕过这种缓冲,随后出现看似奇怪的行为。 【参考方案1】:

&lt;stdio.h&gt; 输入/输出例程为buffered(请参阅stdio(3) 和setbuf(3)。您需要调用fflush(3)(在最近的libc 上,如果您使用@987654330 阅读,则隐式调用stdout @ 或 scanf)。而且您确实应该避免在同一输出或输入上混合文件描述符和 FILE 句柄(请参阅 fileno(3),但始终调用 fflush....)。 所以替换

         printf("Enter the filename: ");
         read(STDIN_FILENO, userInput, sizeof(userInput));

         printf("Enter the filename: \n");
         fflush(NULL);
         if (!fgets(userInput,sizeof(userInput),stdin))
            perror("fgets"); exit(EXIT_FAILURE); ;

实际上,如果您保留非常重要的终止 \n(换行符),则可以避免使用 fflush。如果您不想要任何换行符,最好致电 fflush(但有些 libc 会为您调用)。

调用fflush 太多或太频繁比调用它太少或不够有害(因为在所有已刷新的流上它是无操作的)。

但是您应该了解getline(3)(以避免固定长度的行)。在 Linux 和 GNU 系统上,readline 值得使用:它使您能够给出一个性感的提示,并且您的用户可以编辑键入的行。

【讨论】:

如果您使用标准 I/O 函数,那么(大多数实现)标准 I/O 将协调事物,以便标准输入上的读取首先刷新标准输出。 fflush(NULL) 解决了这个问题 - 但是,这个程序的重点是避免 stdio 并使用低级 i/o - 为什么 stdio 缓冲区会干扰? 出于性能原因,缓冲是必不可少的。过于频繁地调用writeread - 例如。对于每个单独的字节 - 会大大减慢您的程序,因为系统调用很昂贵!【参考方案2】:

您的提示永远不会出现,因为您使用 read() 而不是标准 I/O 函数之一(scanf()fgets() 等)来获取输入。在调用read()之前更改输入函数或使用fflush(stdout)fflush(0)

您的 read 包含换行符,因此 open 尝试打开名称末尾带有换行符的文件。该文件不存在,因此打开失败。


    printf("Enter the filename: ");
    if (fgets(userInput, sizeof(userInput), stdin) == 0)
    
        fprintf(stderr, "Oops!\n");
        exit(1);
    
    userInput[strlen(userInput)-1] = '\0';
    if ((input_file1 = open(userInput, O_RDONLY)) < 0)
    
        perror(userInput);
        exit(1);
    

    while ((n = read(input_file1, buffer, sizeof(buffer))) > 0)
    
        if (printf("%.*s", n, buffer)) != n)
        
            perror("failed to write to standard-out");
            close(input_file1);
            exit(1);
        
    
    close(input_file1);

【讨论】:

我将尝试用 \0 替换换行符,就像您在答案中写的那样。刚看到。谢谢。

以上是关于C 低级标准输入以接受文件名,然后将文件内容打印到标准输出的主要内容,如果未能解决你的问题,请参考以下文章

CentOS 文件管理命令

文件管理命令

linux中基础命令

Linux文件管理命令

linux学习笔记9--命令cat

标准I/O和管道