C++輸入輸出重定向(3種方法)

2020-07-16 10:05:23
《C++輸入流和輸出流》一節提到,cout 和 cerr、clog 的一個區別是,cout 允許被重定向,而 cerr 和 clog 都不支援。值得一提的是,cin 也允許被重定向。

那麼,什麼是重定向呢?在預設情況下,cin 只能接收從鍵盤輸入的資料,cout 也只能將資料輸出到螢幕上。但通過重定向,cin 可以將指定檔案作為輸入源,即接收檔案中早已準備好的資料,同樣 cout 可以將原本要輸出到螢幕上的資料轉而寫到指定檔案中。

C++ 中,實現重定向的常用方式有 3 種,本節將一一做詳細講解。

C++ freopen()函數實現重定向

freopen() 定義在<stdio.h>標頭檔案中,是 C 語言標準庫中的函數,專門用於重定向輸入流(包括 scanf()、gets() 等)和輸出流(包括 printf()、puts() 等)。值得一提的是,該函數也可以對 C++ 中的 cin 和 cout 進行重定向。

舉個例子:
#include <iostream>    //cin、cout
#include <string>      //string
#include <stdio.h>     //freopen
using namespace std;
int main()  
{
    string name, url;
    //將標準輸入流重定向到 in.txt 檔案
    freopen("in.txt", "r", stdin);
    cin >> name >> url;

    //將標準輸出重定向到 out.txt檔案
    freopen("out.txt", "w", stdout); 
    cout << name << "n" << url;
    return 0;
}
執行此程式之前,我們需要找到當前程式檔案所在的目錄,並手動建立一個 in.txt 檔案,其包含的內容如下:

C++
http://c.biancheng.net/cplus/

建立好 in.txt 檔案之後,可以執行此程式,其執行結果為:

    <--控制台中,既不需要手動輸入,也沒有任何輸出

與此同時,in.txt 檔案所在目錄下會自動生成一個 out.txt 檔案,其包含的內容和 in.txt 檔案相同:

C++
http://c.biancheng.net/cplus/

顯然,通過 2 次呼叫 freopen() 函數,分別對輸入流和輸出流重定向,使得 cin 不再接收由鍵盤輸入的資料,而是直接從 in.txt 檔案中獲取資料;同樣,cout 也不再將資料輸出到螢幕上,而是寫入到 out.txt 檔案中。

C++ rdbuf()函數實現重定向

rdbuf() 函數定義在<ios>標頭檔案中,專門用於實現 C++ 輸入輸出流的重定向。

值得一提的是,ios 作為 istream 和 ostream 類的基礎類別,rdbuf() 函數也被繼承,因此 cin 和 cout 可以直接呼叫該函數實現重定向。

rdbuf() 函數的語法格式有 2 種,分別為:
streambuf * rdbuf() const;
streambuf * rdbuf(streambuf * sb);

streambuf 是 C++ 標準庫中用於表示緩衝區的類,該類的指標物件用於代指某個具體的流緩衝區。

其中,第一種語法格式僅是返回一個指向當前流緩衝區的指標;第二種語法格式用於將 sb 指向的緩衝區設定為當前流的新緩衝區,並返回一個指向舊緩衝區的物件。

舉個例子:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    //開啟 in.txt 檔案,等待讀取
    ifstream fin("in.txt");
    //開啟 out.txt 檔案,等待寫入
    ofstream fout("out.txt");
    streambuf *oldcin;
    streambuf *oldcout;
    char a[100];
    //用 rdbuf() 重新定向,返回舊輸入流緩衝區指標
    oldcin = cin.rdbuf(fin.rdbuf());
    //從input.txt檔案讀入
    cin >> a;
    //用 rdbuf() 重新定向,返回舊輸出流緩衝區指標
    oldcout = cout.rdbuf(fout.rdbuf());
    //寫入 out.txt
    cout << a << endl;

    //還原標準輸入輸出流
    cin.rdbuf(oldcin); // 恢復鍵盤輸入
    cout.rdbuf(oldcout); //恢復螢幕輸出
    //開啟的檔案,最終需要手動關閉
    fin.close();
    fout.close();
    return 0;
}

程式中涉及到的檔案操作,後續章節會做詳細講解,讀者只需領悟 rdbuf() 函數的用法即可。

仍以前面建立好的 in.txt 檔案為例,執行此程式後,控制台不會輸出任何資料,而是會在該專案的目錄下生成一個 out.txt 檔案,其中就存有該程式的執行結果:

C++
http://c.biancheng.net/cplus/

C++通過控制台實現重定向

以上 2 種方法,都是從程式碼層面實現輸入輸出流的重定向。除此之外,我們還可以通過控制台實現輸入輸出的重定向。

舉個例子,假設有如下程式碼(檔名為 demo.cpp):
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string name, url;
    cin >> name >> url;
    cout << name << 'n' << url;
    return 0;
}
通過編譯、連結後,會生成一個 demo.exe 可執行檔案,該執行檔案可以雙擊執行,也可以在控制台上執行。例如,開啟控制台(Windows 系統下指的是 CMD命令列視窗,Linux 系統下指的是 Shell 終端),並輸入如下指令:

C:Usersmengma>D:demo.exe
C++ http://c.biancheng.net/cplus/
C++
http://c.biancheng.net/cplus/

可以看到,demo.ext 成功被執行,但程式中的 cin 和 cout 並沒有被重定向,因此這裡仍需要我們手動輸入測試資料。

在此基礎上,繼續在控制台執行如下指令:

C:Usersmengma>D:demo.exe <in.txt >out.txt

需要注意的是,執行此命令前,需保證 C:Usersmengma 目錄下有 in.txt 檔案。

執行後會發現,控制台沒有任何輸出。這是因為,我們使用了"<in.txt"對程式中的 cin 輸入流做了重定向,同時還用 ">out.txt"對程式中的 cout 輸出流做了重定向。

如果此時讀者進入 C:Usersmengma 目錄就會發現,當前目錄生成了一個 out.txt 檔案,其中就儲存了 demo.ext 的執行結果。

在控制台中使用 > 或者 < 實現重定向的方式,DOS、windows、Linux 以及 UNIX 都能自動識別。