七、輸入/輸出流

流類簡介

C++中凡是數(shù)據(jù)從一個(gè)地方傳輸?shù)搅硪粋€(gè)地方的操作都是的操作。因此,一般意義下的讀操作在流數(shù)據(jù)抽象中被稱為(從流中)“提取”,寫操作被稱為(向流中)“插入”。

iostream流類庫的類關(guān)系圖如下:

流類庫關(guān)系圖

圖中箭頭代表派生關(guān)系。ios是抽象基類,提供輸入/輸出所需的公共操作,它派生出兩個(gè)類istreamostream。為了避免多重繼承的二義性,從ios派生istreamostream時(shí),均使用了virtual關(guān)鍵字(虛繼承)。

stream類提供了流的大部分輸入操作,對系統(tǒng)預(yù)定義的所有輸入流重載提取運(yùn)算符>>。ostream類對系統(tǒng)預(yù)定義的所有輸出流重載插入運(yùn)算符<<

C++的iostream類庫提供了數(shù)百種I/O功能,iostream類庫的接口部分包含在幾個(gè)頭文件中。常見的頭文件有以下3個(gè):

  1. iostream:包含操作所有輸入/輸出流所需要的基本信息,因此大多數(shù)C++程序都應(yīng)包含這個(gè)頭文件。該文件含有4個(gè)標(biāo)準(zhǔn)流對象,提供了無格式化和格式化的I/O功能。
  2. iomanip:包含格式化I/O的帶參數(shù)流操縱符,可用于指定數(shù)據(jù)輸入/輸出的格式。
  3. fstream:包含處理文件的有關(guān)信息,提供建立文件、讀/寫文件的各種操作接口。

標(biāo)準(zhǔn)流對象

C++在頭文件iostream中為了用戶預(yù)定義了4個(gè)標(biāo)準(zhǔn)流對象,分別是:

  • cin(標(biāo)準(zhǔn)輸入流),cin與標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)相關(guān)聯(lián),用于讀取數(shù)據(jù),可以被重定向?yàn)閺奈募凶x取數(shù)據(jù)。
  • cout(標(biāo)準(zhǔn)輸出流),cout與標(biāo)準(zhǔn)輸出設(shè)備(顯示器)相關(guān)聯(lián),用于輸出數(shù)據(jù),可以被重定向?yàn)橄蛭募飳懭霐?shù)據(jù)。
  • cerr(非緩沖錯(cuò)誤輸出流),cerr與標(biāo)準(zhǔn)錯(cuò)誤信息輸出設(shè)備(顯示器)相關(guān)聯(lián)(非緩沖),用于輸出出錯(cuò)信息,不能被重定向。
  • clog(緩沖錯(cuò)誤輸出流),clog與標(biāo)準(zhǔn)錯(cuò)誤信息輸出設(shè)備相關(guān)聯(lián)(緩沖),用于輸出出錯(cuò)信息,不能被重定向。

在實(shí)際中,cin常用于從鍵盤輸入數(shù)據(jù),是流類istream的對象。cout常用于向屏幕輸出數(shù)據(jù),是流類ostream的對象。

#include <iostream>
using namespace std;

int main() {
    int x, y;
    cin >> x >> y;
    //函數(shù)`freopen()`的功能是將`stream`按`mode`指定的模式重定向到路徑`path`指向的文件。
    //將標(biāo)準(zhǔn)輸出定向到文件test.txt
    freopen("test.txt", "w", stdout);
    
    if (y == 0) {
        cerr << "error" << endl;
    } else {
        cout << x << " / " << y << " = " << x / y << endl;
    }

    return 0;
};

控制I/O格式

C++進(jìn)行I/O格式控制的方式一般有使用流操縱符、設(shè)置標(biāo)志字和調(diào)用成員函數(shù)。

流操縱符

流操縱符 作用
endl 輸出一個(gè)新行符,并清空流
ends 輸出字符串結(jié)束,并清空流
flush 清空流緩沖區(qū)
dec*(默認(rèn)) 以十進(jìn)制形式輸入/輸出整數(shù)
hex 以十六進(jìn)制形式輸入或輸出整數(shù)
cot 以八進(jìn)制形式輸入或輸出整數(shù)
ws 提取空白字符
fixed 以普通小數(shù)形式輸出浮點(diǎn)數(shù)
scientific 以科學(xué)計(jì)數(shù)法形式輸出浮點(diǎn)數(shù)
left 左對齊,即在寬度不足時(shí)將填充字符添加到右邊
right* 右對齊,即在寬度不足時(shí)將填充字符添加到左邊
setbase(int b) 設(shè)置輸出整數(shù)時(shí)的進(jìn)制,b為8、10、16
setw(int w) 指定輸出寬度為w個(gè)字符,或輸入字符串時(shí)讀入w個(gè)字符。
一次有效。
setfill(int c) 在指定輸出寬度的情況下,
輸出的寬度不足時(shí)用ASCⅡ碼為c的字符填充(默認(rèn)情況是用空格填充)
setprecision(int n) 設(shè)置輸出浮點(diǎn)數(shù)的精度為n。
在使用非fixed且非scientific方式輸出的情況下,
n即為有效數(shù)字最多的位數(shù)。
如果有效數(shù)字位數(shù)超過n,
則小數(shù)部分四舍五入,
或自動變?yōu)榭茖W(xué)計(jì)數(shù)法輸出并保留一共n位有效數(shù)字;
在使用fixed方式和scientific方式輸出的情況下,
n是小數(shù)點(diǎn)后面應(yīng)保留的位數(shù)。
setiosflags(fmtflags f) 通用操縱符。將格式標(biāo)志f所對應(yīng)的格式標(biāo)志位置為1
resetiosflags(fmtflags f) 通用操縱符。將格式標(biāo)志f所對應(yīng)的格式標(biāo)志位置為0(清除)
boolapha turefalse輸出為字符串
noboolapha* turefalse輸出為10
showbase 輸出表示數(shù)值進(jìn)制的前綴
noshowbase* 不輸出表示數(shù)值進(jìn)制的前綴
showpoint 總是輸出小數(shù)點(diǎn)
noshowpoint* 只有當(dāng)小數(shù)部分存在時(shí)才顯示小數(shù)點(diǎn)
showpos 在非負(fù)數(shù)值中顯示+
noshowpos* 在非負(fù)數(shù)值中不顯示+
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int n = 65535, m = 20;
    
    //1.分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
    cout << "1)" << n << " = " << hex << n << " = " << oct << n << endl;
    //1)65535 = ffff = 177777
    
    //2.使用setbase分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
    cout << "2)" << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
    //2)20 = 14 = 24
    
    //3.使用showbase和setbase分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
    cout << "3)" << showbase;//輸出表示數(shù)值進(jìn)制的前綴
    cout << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
    //3)20 = 0x14 = 024

    return 0;
};

標(biāo)志字

標(biāo)志常量名 含義 輸入/輸出
ios::skipws 0x0001 跳過輸入中的空白 I
ios::left 0x0002 按輸出域左對齊,用填充字符填充右邊 O
ios::right* 0x0004 按輸入域右對齊,用填充字符填充做左邊 O
ios::internal 0x0008 在符號位或基數(shù)指示符后填入字符 O
ios::dec* 0x0010 轉(zhuǎn)換為十進(jìn)制基數(shù)形式 I/O
ios::oct 0x0020 轉(zhuǎn)換為八進(jìn)制基數(shù)形式 I/O
ios::hex 0x0040 轉(zhuǎn)換為十六進(jìn)制基數(shù)形式 I/O
ios::showbase 0x0080 在輸出中顯示基數(shù)指示符 O
ios::showpoint 0x0100 在輸出浮點(diǎn)數(shù)時(shí)必須帶小數(shù)點(diǎn)和尾部的0 O
ios::uppercase 0x0200 以大寫字母表示十六進(jìn)制數(shù),科學(xué)計(jì)數(shù)法使用大寫字母 O
ios::showpos 0x0400 正數(shù)前面加+ O
ios::scientific 0x0800 科學(xué)計(jì)數(shù)法顯示浮點(diǎn)數(shù) O
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double x = 12.34;
    
    cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;
    cout << "2)" << setiosflags(ios::fixed) << x << endl;
    cout << "3)" << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << x << end;
    cout << "4)" << resetiosflags(ios::showpos) << x << endl;
    //1)+1.234000e+001
    //2)+12.34
    //3)+1.234000e+001
    //4)1.234000e+001

    return 0;
};

調(diào)用cout的成員函數(shù)

成員函數(shù) 作用相同的流操作符
precision(int np) setprecision(np)
width(int nw) setw(nw)
fill(char cFill) setfill(cFill)
setf(long iFlags) setiosflags(iFlags)
unsetf(long iFlags) resetiosflags(iFlags)
#include <iostream>
using namespace std;

int main(){
    double values[] = {
        1.23,
        20.3456,
        300.4567,
        4000.45678,
        50000.1234567
    };
    
    cout.fill('*');//設(shè)置填充字符為`*`
    for (int i = 0; i < sizeof(values) / sizeof(double); i++) {
        cout << "values[" << i << "] = (";
        cout.width(10);//設(shè)置輸出寬度
        cout << values[i] << ")" << endl;
    }
    /*
    values[0] = (******1.23)
    values[1] = (***20.3456)
    values[2] = (***300.457)
    values[3] = (***4000.46)
    values[4] = (***50000.1)
    */
    
    cout.fill(' ');//設(shè)置填充字符為空格
    for (int j = 0; j < sizefo(values) / sizeof(double); j++) {
        cout << "values[" << j << "] = (" 
        cout.width(10);//設(shè)置輸出寬度
        cout.precision(j + 3);//設(shè)置保留有效數(shù)字
        cout << values[j] << ")" << endl;
    }
    /*
    values[0] = (     1.23)
    values[1] = (    20.35)
    values[2] = (   300.46)
    values[3] = (  4000.46)
    values[4] = ( 50000.12)
    */
    
    return 0;
};

調(diào)用cin的成員函數(shù)

istream類提供了一些公有成員函數(shù),它們可以以不同的方式提取輸入流中的數(shù)據(jù)。

get()函數(shù)

#include <iostream>
using namespace std;
 
int main() {
    int n = 0;
    char ch;
    //當(dāng)文件沒有結(jié)束時(shí)繼續(xù)進(jìn)行循環(huán)
    while ((ch = cin.get()) != EOF) {
        cout.put(ch);
        n++;
    }
    cout << "輸入字符共計(jì):" << n << endl;
};

Windows環(huán)境下,當(dāng)進(jìn)行鍵盤輸入時(shí),在單獨(dú)的一行按ctrl + z組合鍵后再按enter鍵就代表文件輸入結(jié)束。

getline()函數(shù)

getline()成員函數(shù)的原型如下:

istream & getline(char *buf, int bufSize);

其功能是從輸入流中的當(dāng)前字符開始讀取bufSize - 1個(gè)字符到緩沖區(qū)buf,或讀到\n為止(哪個(gè)條件先滿足即按哪個(gè)執(zhí)行)。函數(shù)會在buf中讀入數(shù)據(jù)的結(jié)尾自動添加串結(jié)束標(biāo)記\0。

istream & getline(char *buf, int bufSize, char delim);

其功能是從輸入流中的當(dāng)前字符開始讀取bufSize - 1個(gè)字符到緩沖區(qū)buf,或讀到字符delim為止(哪個(gè)條件先滿足即按哪個(gè)執(zhí)行)。函數(shù)會在buf中讀入數(shù)據(jù)的結(jié)尾自動添加\0

兩者的區(qū)別在于,前者是讀到\n為止,后者是讀到指定字符delim為止。字符\ndelim都不會被存入buf中,但會從輸入流中取走。

函數(shù)getline()的返回值是函數(shù)所作用的對象的引用。如果輸入流中\ndelim之前的字符個(gè)數(shù)達(dá)到或超過bufSize,則會導(dǎo)致讀入操作出錯(cuò),其結(jié)果是:雖然本次讀入已經(jīng)完成,但是之后的讀入都會失敗。

#include <iostream>
using namespace std;

int main() {
    char buf[10];
    int i = 0;
    //若輸入流的一行超過9個(gè)字符,則會出錯(cuò)
    while (cin.getline(buf, 10)) {
        cout << ++i << ":" << buf << endl;
    }
    cout << "last:" << buf << endl;
    
    return 0;
};

eof()函數(shù)

eof()成員函數(shù)的原型如下:

bool eof();

eof()函數(shù)用于判斷輸入流是否已經(jīng)結(jié)束。返回值為true表示輸入結(jié)束。

在應(yīng)用程序中可以用eof()函數(shù)測試是否到達(dá)文件尾,當(dāng)文件操作結(jié)束遇到文件尾時(shí),函數(shù)返回1;否則返回0。

ignore()函數(shù)

ignore()成員函數(shù)的原型如下:

istream & ignore(int n = 1, int delim = EOF);

此函數(shù)的作用是跳過輸入流中的n個(gè)字符,或跳過delim及其之前的所有字符(哪個(gè)條件先滿足就按哪個(gè)執(zhí)行)。兩個(gè)參數(shù)都有默認(rèn)值。因此cin.ignore()等效于cin.ignore(1, EOF),即跳過一個(gè)字符。該函數(shù)常用于跳過輸入中的無用部分,以便提取有用的部分。

#include <iostream>
using namespace std;

int main() {
    char str[30];
    while (!cin.eof()) {
        cin.ignore(10, ':');
        if (!cin.eof()) {
            cin >> str;
            cout << str << endl;
        }
    }

    return 0;
};

peek()函數(shù)

peek()成員函數(shù)的原型如下:

int peek();

函數(shù)peek()返回輸入流中的當(dāng)前字符,但是并不將該字符從輸入流中取走,相當(dāng)于只是“看了一眼”將要讀入的下一個(gè)字符,因此叫“窺視”。

cin.peek()不會跳過輸入流中的空格和回車符。在輸入流已經(jīng)結(jié)束的情況下,cin.peek()返回EOF

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容