1. 程式人生 > >程序通訊之二 管道技術第一篇 輸入輸出的重定向

程序通訊之二 管道技術第一篇 輸入輸出的重定向

               

繼上一篇《程序通訊之一使用WM_COPYDATA C++C#實現》,程序通訊之二將分為三篇文章講解如何使用管道技術來完成程序通訊功能。三篇文章目錄如下:

本篇將介紹輸入輸出的重定向問題,先來看一個小小的例項,設有一個程式,該程式的輸入輸出為標準輸入輸出即從鍵盤上輸入,輸出到螢幕。現在要重定向輸入法輸出,使程式從檔案中讀取資料,處理後輸出到檔案。程式程式碼如下(稱此程式為示例程式):

#include <stdio.h>int main()int n; while (scanf("%d", &n) != EOF) //標準輸入時,可按ctrl+z來輸入EOF {  n *= 2
;  printf("%d\n", n); }}

試給出幾種不同的實現方法,另外如果沒有程式程式碼,只有可執行檔案,又應該如何做了?

實現方法一使用C語言的freopen()函式

函式功能:重定向控制檯的輸入輸出

函式原型:

FILE *freopen(

const char *path,

const char *mode,

FILE *stream

);

函式說明:

第一個引數為檔案指標(也可以用來指向標準輸入輸出)。

第二個引數為開啟方式,"w"表示寫,"r"表示讀,"a"表示追加。其它設定可以參考MSDN

第三個引數為FILE型別的指標,傳入stdin表示標準輸入,傳入stdout表示標準輸出。

這樣用只要用簡單一句freopen

("infile.txt", "r", stdin);就可以使程式中的scanf()函式從檔案中讀取資料作為輸入,同樣freopen("outfile.txt", "w", stdout);可以使程式中的printf()函式將輸出由標準輸出改成輸出到檔案。現在有個問題,將程式的輸入輸出重定向到檔案後,還能改回到標準輸入輸出嗎?答案是可以的,對第一個引數傳入"CON"這個字串就可以了(linux"/dev/console")。

下面就給出修改後的程式碼:

//直接使用freopen()函式 來改變控制檯的標準輸入輸出#include <stdio.h>int main()//將控制檯的標準輸入輸出改成從檔案中讀取寫入
 FILE *pFileRead = freopen("infile.txt", "r", stdin); FILE *pFileWrite = freopen("outfile.txt", "w", stdout); int n; while (scanf("%d", &n) != EOF) {  n *= 2;  printf("%d\n", n); } fclose(pFileRead); fclose(pFileWrite); //回到到控制檯的標準輸入輸出 windows為"CON" linux為"/dev/console" freopen("CON", "r", stdin); freopen("CON", "w", stdout);  printf("Finish 輸入0表示結束:\n"); do{  scanf("%d", &n); }while (n != 0);  return 0;}

執行結果如下圖所示:

 

可以看出該程式的輸出輸入已經完成了重定向。

實現方法2 使用C++的ifstream和ofstream類

有些場合使用類來完成輸入輸出的重定向任務會更加方便和習慣一些。所幸C++中就有ifstreamofstream這二個類來幫助我們完成這一任務。這個二類的詳細功能就不細說了。下面介紹下如何使用這二個類來重定向程式的輸入輸出(看的時候看慢點喔,不會會被很多類名給搞暈去^_^)。

這二個類可以以讀的方式和寫的方法開啟一個檔案(ifstream的首字母i就表示in,而ofstream的首字母o就表示out),在iosfwd檔案中找到:

    typedef basic_ifstream<char, char_traits<char> > ifstream;

typedef basic_ofstream<char, char_traits<char> > ofstream;

然後可以在fstream檔案中找到basic_ifstream類是繼承於basic_istream類,basic_ofstream類是繼承於basic_ostream類。

然後再來看看C++中大家平常使用的cincout,可以在iostream檔案中找到cincout的定義,這二個實際是istream型別和ostream型別的變數:

extern _CRTIMPistream cin;

extern _CRTIMPostream cout;

然後在iosfwd檔案中可以找到:

typedef basic_istream<char, char_traits<char> > istream;

typedef basic_ostream<char, char_traits<char> > ostream;

明顯cincoutifstream類和ofstream類有著非常密切關係——cinbasic_istream類的變數,而ifstream則是basic_istream類的派生類。coutbasic_ostream類的變數,而ofstream則是basic_ostream類的派生類。

有了這個後,猜測很可能會有某個成員函式能將它們聯絡到一起,從而讓cin和cout由標準輸入輸出重定向到從檔案中讀取,輸出到檔案。事實上basic_istream類實際是虛繼承於basic_ioso類,basic_ostream類實際是虛繼承於basic_ios類。這二個類都有個rdbuf()成員函式,這個函式允許我們訪問和修改類中一個型別為basic_streambuf類的成員變數。改動這個變數就能重定向輸入輸出。因此對cin和cout呼叫這個rdbuf()函式並傳入ifstreamofstreamrdbuf()就可以將控制檯的標準輸入輸出改成從檔案中讀取和輸出到檔案。

OK,方法既然找到了,那下面就使用C++的方法來重定向輸入輸出:

//使用ifstream和ofstream及cin和cout的rdbuf()#include <iostream>#include <fstream>using namespace std;int main()printf("   使用ifstream和ofstream及cin和cout的rdbuf()來改變控制檯的標準輸入輸出\n");   printf("  --by MoreWindows( http://blog.csdn.net/MoreWindows )--\n\n");  //將控制檯的標準輸入輸出改成從檔案中讀取寫入 ifstream inFile("infile.txt")ofstream outFile("outfile.txt")//儲存原來的輸入輸出方式 streambuf類就是basic_streambuf類 streambuf *strmin_buf = cin.rdbuf(); streambuf *strmout_buf = cout.rdbuf(); printf("開始處理檔案\n....\n"); //重定向到檔案 cin.rdbuf(inFile.rdbuf()); cout.rdbuf(outFile.rdbuf());    //原程式程式碼 int n; while (cin>>n) {  n *= 2;  cout<<n<<endl; } inFile.close(); outFile.close(); //回到控制檯的標準輸入輸出 cin.rdbuf(strmin_buf); cout.rdbuf(strmout_buf); cout<<"檔案已經處理完畢 輸入0表示結束:"<<endldo{  cin>>n; }while (n != 0); return 0;}

執行結果如下圖所示:

 

同樣,這個程式也完成了輸入輸出的重定向。

上面的方法都是建立在修改原始碼的基礎上,如果只有程式檔案即.exe檔案那應該怎麼做了?請參閱下一篇《程序通訊之二 管道技術第二篇 匿名管道

如果覺得本文對您有幫助,請點選支援一下,您的支援是我寫作最大的動力,謝謝。