# I/O Stream 概述 ###### tags: `Competitive Programming Note` 本文已停止更新,新版請至 [WiwiHo 的競程筆記](https://cp.wiwiho.me/) 你可能有聽過「輸入流」和「輸出流」,但是流是什麼呢? 流(stream)就像河流一樣,先從上游流進去的東西會先從下游流出來,而輸入流和輸出流顧名思議,就是用來控制輸入和輸出的東西。簡單來講,你輸入的東西會進入輸入流,然後再依序流往它流向的地方,像是被程式讀取,輸出流也是,程式輸出的東西會先到輸出流,再到它流向的地方,可能是你的 terminal、或是某些檔案,分成多個輸入、輸出流的目的就是為了控管不同的來源和去向。有些流會有「緩衝區」,就是流裡的東西會暫時停在那裡,不會馬上跑到流向的地方。 非常簡略地講解一下 C++ 裡輸入輸出的物件關係(詳細可以看[這裡](http://www.cplusplus.com/reference/ios/))。有兩個類型分別叫 ostream 和 istream,分別是輸出流和輸入流,繼承 ostream 的都是輸出流、繼承 istream 的都是輸入流,然後有另一個類型叫 iostream,它同時繼承 ostream 和 istream,所以它是雙向的,一個例子是 stringstream,待會會提到。 大家應該都知道 cin/cout 的基礎用法了,所有 istream 的用法都和 cin 一樣、所有 ostream 的用法都和 cout 一樣。 ## 標準流 標準流是指三種流:標準輸入流、標準輸出流和標準錯誤流,標準輸入和輸出流就如同其名,分別是輸入流和輸出流,至於標準錯誤流,它是一個輸出流,它們預設都是在 terminal 上做事的,從 terminal 輸入和輸出到 terminal,在 C++ 中,它們三個分別由 cin(繼承 istream)、cout(繼承 ostream)和 cerr(繼承 ostream)控制,也就是大家最常用的輸入輸出流啦。 標準輸出流和標準錯誤流都是輸出流,那它們有什麼分別呢?首先,judge 是只會讀標準輸出流的資訊的,所以你可以輸出一堆 debug 用的訊息到標準錯誤流,忘記刪掉也不會怎麼樣,只要不要造成 TLE 就好了(像是輸出量過大)。而且它們可以被重新導向到不同的地方。 這裡提到了一個東西,叫做「重新導向(redirect)」,標準流不一定要在 terminal 做事,也可以把它導到別的地方去,如果直接在 C++ 寫,用法是這樣的: ```cpp= freopen("filename", "w", stdout); freopen("filename", "w", stderr); freopen("filename", "r", stdin); ``` 這三個分別是把標準輸出、錯誤和輸入流導向到名為 filename 的檔案,在本機測試的時候,輸入或輸出量大時,把標準流導到檔案去是很實用的方法,也很方便,只要加幾行重新導向的程式碼就可以了,而上傳到 judge 前也只要移除這幾行就好。有些比賽例如 USACO,會要求你從特定的檔案輸入輸出。 也可以在 terminal 上做重新導向,在 Linux 的 bash 和 Windows 的 CMD 都是像這樣寫: ```bash= command < in command > out command 2> err command < in > out 2> err command < in > out ``` command 是執行檔名稱,in 是輸入流導向的檔案,out 是輸出流導向的檔案,err 是錯誤流導向的檔案,可以像前三行一樣只重新導向其中一個、也可以像第四行一樣重新導向全部三個,或是像第五行只重新導向其中兩個。 對檔案輸入輸出也可以用 fstream,但比賽理論上用不到,所以有興趣可以自己查。 cin 和 cout 都有緩衝區,所以 cin 從來源讀取的東西會留在緩衝區裡等你用程式讀取,而你讓 cout 輸出的東西也會先留在緩衝區,不會馬上出現在它導向到的地方,讓輸出流真的輸出緩衝區裡的東西的動作叫 flush,手動 flush 的方法是 `cout << flush`,`cout` 也可以換成其他有緩衝區的輸出流,自動 flush 的條件後面會提到。而 cerr 沒有緩衝區,所以你讓 cerr 輸出的東西就會馬上真的輸出出去。