перенаправить stdout/stderr в файл под unix c++ - снова

что я хочу сделать

перенаправить stdout и stderr на один или несколько файлов из C++

зачем он мне нужен

Я использую внешнюю, предварительно скомпилированную стороннюю библиотеку, которая производит смешной объем вывода, который я хотел бы перенаправить в файл журнала, чтобы сохранить консоль чистой.

условия

совместимость не является проблемой, код будет работать только в системах Unix. Перенаправление должно влиять не только на печать в стиле c++(std::cout

то, что я пробовал до сих пор

Я просматривал stackoverflow в течение половины дня, читая несколько ответов людям, имеющим аналогичные проблемы. С помощью этих ответов я смог собрать следующий фрагмент кода:


#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include "unistd.h"

const int stdoutfd(dup(fileno(stdout)));

int redirect_stdout(const char* fname){
  fflush(stdout);
  int newstdout = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |     S_IROTH);
  dup2(newstdout, fileno(stdout));
  close(newstdout);
}

int restore_stdout(){
  fflush(stdout);
  dup2(stdoutfd, fileno(stdout));
  close(stdoutfd);
  return stdoutfd;
}

int main(){
  redirect_stdout("/dev/null");
  std::cout << "invisible 1" << std::endl;
  restore_stdout();
  std::cout << "visible 1" << std::endl;
  redirect_stdout("/dev/null");
  std::cout << "invisible 2" << std::endl;
  restore_stdout();
  std::cout << "visible 2" << std::endl;
  return 0;
}

что бы я ожидаем:

visible 1
visible 2

что я на самом деле вижу

visible 1

то есть при использовании этого механизма в первый раз он работает - но если используется снова, восстановление вывода не будет работать. Может ли кто-нибудь указать мне, что мне нужно изменить, чтобы механизм работал бесконечно часто?

5 ответов


Если вы хотите иметь возможность повторно использовать его, не закрывайте stdoutfd на restore_stdout.


ну я бы лучше использовать freopen()

Использование Синтаксис:

freopen("RedToFile","r",stdout);
or
freopen("/dev/null","a",stdout);

то же самое касается "stderr"


вы ищете что-то вроде этого :-

int main()
{
    // Save original std::cin, std::cout
    std::streambuf *coutbuf = std::cout.rdbuf();
    std::streambuf *cinbuf = std::cin.rdbuf(); 

    std::ofstream out("outfile.txt");
    std::ifstream in("infile.txt");

    //Read from infile.txt using std::cin
    std::cin.rdbuf(in.rdbuf());

    //Write to outfile.txt through std::cout 
    std::cout.rdbuf(out.rdbuf());   

    std::string test;
    std::cin >> test;           //from infile.txt
    std::cout << test << "  "; //to outfile.txt

    //Restore back.
    std::cin.rdbuf(cinbuf);   
    std::cout.rdbuf(coutbuf); 

}

из моего предыдущего ответ


кроме afr0ck ответ freopen() я хочу сказать, что при использовании freopen() мы должны быть осторожны. Когда-то поток, как stdout или stdin возобновлено с назначением нового назначения(здесь '.txt' file) всегда остается для программы, если она не была явно изменена.

freopen("output.txt", "a", stdout);

здесь стандартный выходной поток stdout возобновлено и назначено на '.txt'. После этого всякий раз, когда мы используем printf() или любое другое stdout поток, как - putchar() тогда каждый вывод будет идти в '.txt'. Чтобы вернуть поведение по умолчанию (то есть вывода в консоли/терминале)printf() или putchar() мы можем использовать следующий код -

  • для gcc, дистрибутив linux, как ubuntu -freopen("/dev/tty", "w", stdout);
  • для Mingw C / C++, windows -freopen("CON", "w", stdout);

см. Пример кода ниже -

#include <stdio.h>

int main() {

    printf("No#1. This line goes to terminal/console\n");

    freopen("output.txt", "a", stdout);
    printf("No#2. This line goes to the \"output.txt\" file\n");
    printf("No#3. This line aslo goes to the \"output.txt\" file\n");

    freopen("/dev/tty", "w", stdout); /*for gcc, diffrent linux distro eg. - ubuntu*/
    //freopen("CON", "w", stdout); /*Mingw C++; Windows*/
    printf("No#4. This line again goes to terminal/console\n");        

}

этот код генерирует '.txt' файл в вашем текущем каталоге и No#2 и No#3 будут напечатаны в '.txt'.

спасибо


для iostreams C++ вы можете использовать не-const перегрузку rdbuf установить std::cout до std::filebuf. (Это лучше всего сделать средство класса RAII, так как вы должны восстановить его раньше покидаю мэйн.) Для C FILE*, вы можете использовать freopen, но Не думаю, что вы сможете его восстановить.

FWIW: оба этих решения используют только стандартный C++ или C, поэтому должно быть портативным.