Jak przekierować cin i cout do plików?

Odpowiedzi:

226

Oto działający przykład tego, co chcesz zrobić. Przeczytaj komentarze, aby dowiedzieć się, co robi każdy wiersz w kodzie. Przetestowałem to na moim komputerze z gcc 4.6.1; to działa dobrze.

#include <iostream>
#include <fstream>
#include <string>

void f()
{
    std::string line;
    while(std::getline(std::cin, line))  //input from the file in.txt
    {
        std::cout << line << "\n";   //output to the file out.txt
    }
}
int main()
{
    std::ifstream in("in.txt");
    std::streambuf *cinbuf = std::cin.rdbuf(); //save old buf
    std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!

    std::ofstream out("out.txt");
    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!

    std::string word;
    std::cin >> word;           //input from the file in.txt
    std::cout << word << "  ";  //output to the file out.txt

    f(); //call function


    std::cin.rdbuf(cinbuf);   //reset to standard input again
    std::cout.rdbuf(coutbuf); //reset to standard output again

    std::cin >> word;   //input from the standard input
    std::cout << word;  //output to the standard input
}

Możesz zapisać i przekierować w jednej linii jako:

auto cinbuf = std::cin.rdbuf(in.rdbuf()); //save and redirect

Tutaj std::cin.rdbuf(in.rdbuf())ustawia std::cin'sbufor na, in.rdbuf()a następnie zwraca stary bufor skojarzony z std::cin. To samo można zrobić z std::cout- lub dowolnym strumieniem, jeśli o to chodzi.

Mam nadzieję, że to pomoże.

Nawaz
źródło
4
Czy muszę zamknąć pliki, zanim zresetuję cin i cout do standardowego IO?
updogliu
3
@updogliu: Nie. Jeśli chcesz, możesz używać ini, odpowiednio, outdo odczytu i zapisu in.txtoraz out.txt. Ponadto pliki zostaną automatycznie zamknięte ini outwyjdą poza zakres.
Nawaz
1
To rozwiązanie podoba mi się bardziej niż to, freopenponieważ nie mogę już odzyskać swoich stdoutpleców, jeśli używam freopen. stackoverflow.com/questions/26699524/ ...
xxks-kkk
92

Tylko napisz

#include <cstdio>
#include <iostream>
using namespace std;

int main()
{
    freopen("output.txt","w",stdout);
    cout<<"write in file";
    return 0;
}
Tsotne Tabidze
źródło
16
To jest przekierowanie stdout, a nie cout.
updogliu
5
Spowoduje to również przekierowanie printf, co w niektórych przypadkach może być dobrą rzeczą.
JDiMatteo,
5
@AkshayLAradhya Nie podczas ustawiania std::sync_with_studio(false);, chociaż domyślnie jest ustawione na true.
vsoftco
2
@ PřemyslŠťastný dlaczego?
reggaeguitar
4
Gdyby odpowiedzi były równe pod względem funkcjonalności, odpowiednikiem tego w C ++ byłoby ofstream out("out.txt"); cout.rdbuf(out.rdbuf());- tylko jedna dodatkowa linia i jest przenośna. Nie tak dużo prostsze :)
nevelis
22

Oto krótki fragment kodu do shadowingu cin / cout przydatnego w konkursach programistycznych:

#include <bits/stdc++.h>

using namespace std;

int main() {
    ifstream cin("input.txt");
    ofstream cout("output.txt");

    int a, b;   
    cin >> a >> b;
    cout << a + b << endl;
}

Daje to dodatkową korzyść, że zwykłe strumienie fstreams są szybsze niż synchronizowane strumienie stdio. Ale to działa tylko w zakresie pojedynczej funkcji.

Globalne przekierowanie cin / cout można zapisać jako:

#include <bits/stdc++.h>

using namespace std;

void func() {
    int a, b;
    std::cin >> a >> b;
    std::cout << a + b << endl;
}

int main() {
    ifstream cin("input.txt");
    ofstream cout("output.txt");

    // optional performance optimizations    
    ios_base::sync_with_stdio(false);
    std::cin.tie(0);

    std::cin.rdbuf(cin.rdbuf());
    std::cout.rdbuf(cout.rdbuf());

    func();
}

Zauważ, że ios_base::sync_with_stdiorównież resetuje sięstd::cin.rdbuf . Więc kolejność ma znaczenie.

Zobacz też Znaczenie ios_base :: sync_with_stdio (false); cin.tie (NULL);

Strumienie standardowe io można również łatwo tworzyć cienie w zakresie pojedynczego pliku, co jest przydatne w przypadku programowania konkurencyjnego:

#include <bits/stdc++.h>

using std::endl;

std::ifstream cin("input.txt");
std::ofstream cout("output.txt");

int a, b;

void read() {
    cin >> a >> b;
}

void write() {
    cout << a + b << endl;
}

int main() {
    read();
    write();
}

Ale w tym przypadku musimy wybierać stddeklaracje pojedynczo i unikać, using namespace std;ponieważ dałoby to błąd niejednoznaczności:

error: reference to 'cin' is ambiguous
     cin >> a >> b;
     ^
note: candidates are: 
std::ifstream cin
    ifstream cin("input.txt");
             ^
    In file test.cpp
std::istream std::cin
    extern istream cin;  /// Linked to standard input
                   ^

Zobacz także Jak prawidłowo używać przestrzeni nazw w C ++? , Dlaczego „używanie standardowej przestrzeni nazw” jest uważane za złą praktykę? i Jak rozwiązać konflikt nazw między przestrzenią nazw C ++ a funkcją globalną?

Vadzim
źródło
14

zakładając, że nazwa programu kompilacji to x.exe, a $ to powłoka systemu lub znak zachęty

$ x <infile >outfile 

weźmie dane wejściowe z infile i wyprowadzi do pliku wyjściowego.

Ahmed Eid
źródło
1
Nie jest to związane z C ++ i kończy się niepowodzeniem w żadnym nietrywialnym przykładzie, na przykład gdy program odradza procesy potomne, które zapisują na konsoli. Przynajmniej taki problem napotkałem próbując takiego przekierowania, stąd dlaczego tu jestem.
ashrasmun
8

Spróbuj tego, aby przekierować cout do pliku.

#include <iostream>
#include <fstream>

int main()
{
    /** backup cout buffer and redirect to out.txt **/
    std::ofstream out("out.txt");

    auto *coutbuf = std::cout.rdbuf();
    std::cout.rdbuf(out.rdbuf());

    std::cout << "This will be redirected to file out.txt" << std::endl;

    /** reset cout buffer **/
    std::cout.rdbuf(coutbuf);

    std::cout << "This will be printed on console" << std::endl;

    return 0;
}

Przeczytaj cały artykuł Użyj std :: rdbuf do przekierowania cin i cout

HaseeB Mir
źródło
2
Odpowiedź na to pytanie została udzielona prawie 6 lat temu (w 2012 r.), Ale dodałeś odpowiedź teraz w 2018 r. Twoja odpowiedź jest taka sama, jak zaakceptowana odpowiedź. Zastanawiam się więc, dlaczego opublikowałeś to, skoro nie masz nic nowego do dodania?
Nawaz
Moja odpowiedź podkreśla tylko wersję cout, a szczegółowa odpowiedź znajduje się w linku poniżej.
HaseeB Mir
1
Co nowego w Twojej odpowiedzi, czego nie ma w zaakceptowanej odpowiedzi?
Nawaz
2
Moja odpowiedź nie łączy przekierowań zarówno cout, jak i cin, moja wersja oddziela się, aby była bardziej czytelna
HaseeB Mir