【问题标题】:C stdout to file using dup使用 dup 到文件的 C 标准输出
【发布时间】:2020-02-28 05:59:26
【问题描述】:

我正在开发一个程序,要求用户输入 s、f 或 0 作为用户输入。 S 将预定义的消息打印到系统,f 将该预定义的消息写入用户作为参数给出的文件。 0 终止程序。

我需要让程序只有一个写入标准输出的写入语句。我必须将打印在标准输出中的预定义消息复制到带有 dup2 的文件中。

现在这两个进程必须通过输入分隔(f 写入文件,而 s 写入标准输出)所以我不确定如何在 switch 语句中实现它。

当您输入 f 时,它不应将任何内容打印到标准输出。

这是我的代码:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/wait.h>

#define BUFFER_SIZE 128
#define PERMS 0666

int main(int argc, char *argv[])
{
    char outBuffer[BUFFER_SIZE] = "This is a message\n";
    int count;
    int fd;
    char input =0;
    int a;
    int c;
    int k[2];
    pipe(k);
    if(argc!=2){
        printf("Provide an valid file as an argument\n");
        exit(1);
    }

    if((fd = open(argv[1],O_CREAT|O_WRONLY|O_APPEND,PERMS)) == -1)
    {
        printf("Could not open file\n");
        exit(1);
    }


        printf("0 to terminate, s to write to stdout, f to write to file\n");
        do{
        scanf(" %c", &input);
        switch(input)
        {

            case 'f':
            if((c = fork()) == 0)
            {
                close(k[0]);
                dup2(fd,1);
                close(k[1]);
             }
             else
             {
                close(k[0]);
                close(k[1]);
                wait(0);
                wait(0);
              }
              break;
            case 's':
            write(1,outBuffer,strlen(outBuffer));
           break;

            default:
            printf("Invalid Choice\n");

         }
     }while(input != '0');

     close(fd);
     return 0;
}

f 现在只是在按下 s(打印 outBufer 消息)或触发默认开关后将标准输出定向到文件

我想要的输出:

f
f
s
This is a message
s
This is a message
f

文件包含:

This is a message
This is a message
This is a message

【问题讨论】:

  • 你必须使用forkdup吗? fprintf 会做任何你想做的事情,因为 stdout 是一个流,就像 fopen 的返回值一样。
  • @LegendofPedro 我不确定 fork,我认为管道可以帮助我解决这个问题......但是是的,我需要使用 dup,否则我只会写入文件。我不知道如何复制它,尤其是当 f 被一个 switch 语句绑定时,该语句将自身与 s 输入分开并以这种方式捕获标准输出。
  • 我得到以下信息:提示: - 打开用户输入的文件。 - 使用 dup(...) 捕获标准输出所指向的内容。 - 然后使用 dup2(...) 在屏幕和文件之间切换。
  • 这个问题是否与stackoverflow.com/questions/58667136/… 相关/相同?

标签: c linux operating-system system dup


【解决方案1】:

这是我对这个问题的看法;我删除了 fork()pipe() 以在 Windows (gcc -g -std=c11 -Wall -c main.c &amp;&amp; gcc main.o -o main.exe) 上本地编译,因为我认为它们不是必需的。当我使用 MSYS2 编译/测试时,我必须显式刷新标准输出,否则在退出之前不会显示信息性消息。

我重构了switch 块,以便我们可以使用breakcontinue 控制主循环,我将其重写为while(1)

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

#define BUFFER_SIZE 128
#define PERMS 0666

int main(int argc, char *argv[]) {
    char outBuffer[BUFFER_SIZE] = "This is a message\n";
    int fd, fd_f, fd_s;
    char input = 0;

    if(argc != 2){
        printf("Provide an valid file as an argument\n");
        exit(1);
    }
    if((fd_f = open(argv[1], O_CREAT|O_WRONLY|O_APPEND, PERMS)) == -1){
        printf("Could not open file\n");
        exit(1);
    }

    printf("0 to terminate, s to write to stdout, f to write to file\n");
    fflush(stdout); // messages are not printed on MSYS2 without explicitly flushing

    fd_s = dup(STDOUT_FILENO); // set fd_s to stdout with dup(1)
    fd = dup(STDOUT_FILENO);
    // if fd is not initialised, calling dup2 will close(0) [i.e. close(stdin)]!
    while(1) {
        scanf("%c", &input);
        fflush(stdin);

        if(input == '0') break;
        else if(input == 'f') dup2(fd_f, fd); // close(fd) and alias fd_f to fd
        else if(input == 's') dup2(fd_s, fd);
        else {
            printf("Invalid Choice\n");
            fflush(stdout);
            continue;
        }
        write(fd, outBuffer, strlen(outBuffer));
    }

    close(fd_f);
    close(fd);
    return 0;
}

输出:

标准输出

>main.exe file.txt
0 to terminate, s to write to stdout, f to write to file
f
f
s
This is a message
s
This is a message
f
p
Invalid Choice
0

>
# ./main.exe file.txt
0 to terminate, s to write to stdout, f to write to file
f
f
s
This is a message
f
p
Invalid Choice
0


文件.txt

This is a message
This is a message
This is a message

【讨论】:

  • 我更愿意将主循环视为while (scanf(" %c", &amp;input) == 1) { … }。这意味着程序在 EOF 处停止。如果格式类似于%d,它也会停在非数字字符上。格式字符串中的前导空格会跳过零个或多个空格字符,包括换行符等。请注意,Using fflush(stdin) 在非 Windows 平台上很棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
相关资源
最近更新 更多