流類庫與輸入輸出 (一)

就像C語言一樣,C++語言中也沒有輸入/輸出語句。但C++編譯系統帶有一個面向對象的輸入/輸出軟件包,它就是I/O流類庫。流是I/O流類的中心概念。首先介紹流的概念,然後介紹流類庫的結構和使用。對於流類庫中類的詳細說明及類成員的描述,請讀者查閱所使用的編譯系統的運行庫參考手冊。 
一、I/O流的概念
    使用VC++6.0在程序中實現I/O有幾種方法:
     C運行庫直接非緩衝的I/O
     ANSI C運行庫流I/O
     控制檯和端口直接I/O    
     Microsoft Foundation類庫
     Microsoft I/O流類庫
    其中I/O流類庫對於緩衝的、格式化文本I/O是很有用的,它是C語言中I/O函數在面向對象的程序設計方法中的一個替換產品。
    我們簡單介紹過,在C++中,將數據從一個對象到另一個對象的流動抽象爲“流”。從流中獲取數據的操作稱爲提取操作,向流中添加數據的操作稱爲插入操作,數據的輸入與輸出就是通過I/O流來實現的。這裏,我們進一步介紹流的概念
    操作系統是將鍵盤、屏幕、打印機和通信端口作爲擴充文件來處理的,而這種處理是通過操作系統的設備驅動程序來實現的。因此,從C++程序員的角度來看,這些設備與磁盤文件是等同的。I/O流類就是用來與這些擴充文件進行交互。
    當程序與外界環境進行信息交換時,存在着兩個對象,一個是程序中的對象,另一個是文件對象。流是一種抽象,它負責在數據的生產者和數據的消費者之間建立聯繫,並管理數據的流動。程序建立一個流對象,並指定這個流對象與某個文件對象建立連接,程序操作流對象,流對象通過文件系統對所連接的文件對象產生作用。由於流對象是程序中的對象與文件對象進行交換的界面,對程序對象而言,文件對象有的特性,流對象也有,所以程序將流對象看作是文件對象的化身。
流所涉及的範圍還遠不止於此,凡是數據從一個地方傳輸到另一個地方的操作都是流的操作。像網絡數據交換、進程數據交換等都是流操作。因此,一般意義下的讀操作在流數據抽象中被稱爲(從流中)提取,寫操作被稱爲(向流中)插入。
I/O流類列表
類    名     說      明 包含文件
抽象流基類
ios 流基類     iostream.h
輸人流類
fstream           通用輸入流類和其他輸入流的基類 iostream.h
ifstream       輸入文件流類   fstream.h
fstream_withassign         cin的輸人流類 iostream.h
istrstream     輸入字符串流類    strstrea.h
輸出流類
ostream       通用輸出流類和其他輸出流的基類 iostream.h
ofstream       輸出文件流類 fstream.h
ostream_withassign        cout、cerr和clog的輸出漉類 iostream.h
ostrstream           輸出字符串流類 strstrea.h
輸入/輸出流類
iostream         通用輸入/輸出流類和其他輸入/輸出流的基類 iostream.h
fstream       輸入/輸出文件流類   fstream.h
strstream        輸人/輸出字符串流類 strstrea.h
stdiostream        標準I/0文件的輸入/輸出類 stdiostr.h
流緩衝區類
streambuf       抽象流緩衝區基類 iostream.h
filebuf        磁盤文件的流緩衝區類 fstream.h
strstreambuf        字符串的流緩衝區類 strstrea.h
stdiobuf     標準I/O文件的流緩衝區類    stdiostr.h
預先定義的流初始化類
iostream-init   預先定義的流初始化類     iostream.h
 
  
二、輸出流
    一個輸出流對象是信息流動的目標,最重要的三個輸出流是ostream,ofstream和 ostrstream。
    ostream類通過派生類ostream_withassign支持預先定義的流對象:
    &S226;cout標準輸出
    &S226;cerr標準錯誤輸出,沒有緩衝,發送給它的內容立即被輸出。
    &S226;clog類似於cerr,但是有緩衝,緩衝區滿時被輸出。
    從ostream和ostream_withassign構造的對象很少,通常用於預先定義的對象。 ostream類可以用於緩衝的或非緩衝的操作,最適合於順序文本模式輸出。

 ofstream類支持磁盤文件輸出。如果你需要一個只輸出的磁盤文件,可以構造一個 ofstream類的對象。在打開文件之前或之後可以指定ofstream對象接受二進制或文本模式數據。很多格式化選項和成員函數可以應用於ofstream對象,包括基類ios和ostream的所有功能。
如果在構造函數中指定一個文件名,當構造這個文件時該文件是自動打開的。否則,你可以在調用缺省構造函數之後使用open成員函數打開文件,或者在一個由文件指示符標識的打開文件基礎上構造一個ofstream對象。 
(一)構造輸出流對象
    如果你僅使用預先定義的cout、cerr或clog對象,就不需要構造一個輸出流。例如,在本章之前的例題中,我們都是將信息輸出到標準輸出設備,使用的是cout。如果要使用文件流將信息輸出到文件,便需要使用構造函數來建立流對象。
    構造輸出文件流的常用方法如下:
    &S226;使用缺省構造函數,然後調用open成員函數,例如:
    ofstream myFile;    //聲明一個靜態輸出文件流對象
myFile.open("filename",iosmode),    //打開文件,使流對象與文件建立聯繫
或:
    ofstream*  pmyFile=new ofstream;    //建立一個動態的輸出文件流對象
    pmyFile->open("filename",iosmode);    //打開文件,使流對象與文件建立聯繫
    &S226;在調用構造函數時指定文件名和模式,
    ofstream myFile("filename",iosmode);
稍後會詳細介紹open成員函數。 
(二)使用插入運算符和控制格式
    本小節介紹如何控制輸出格式以及如何爲自己的類建立插入運算符。插入(<<)運算符是所有標準C++數據類型預先設計的,用於傳送字節到一個輸出流對象。插入運算符與預先定義的操縱符一起工作,用來控制輸出格式。
    1.輸出寬度
    爲了調整輸出,可以通過在流中放人setw操縱符或調用width成員函數爲每個項 (item)指定輸出寬度。下面的例子在一列中以至少10個字符寬按右對齊方式輸出數值:
例  使用width函數控制輸出寬度
#i nclude<iostream.h>
void main()
{
    double s[]={1.23,35.36,653.7,4358.24};
    for(int i=0;i<4;i++)
    {
  cout.width(10);
  cout<<s[i]<<"/n";
    }  
}
其輸出結果是:
    1.23
   35.26
  653.7
 4358.24
    從程序的輸出結果可以看到,在少於10個字符寬的數值前加入了引導空格。
空格是缺省的填充符,當輸出的數據不能充滿指定的寬度時,系統會自動以空格填充,也可以指定用別的字符來填充。使用fill成員函數可以爲已經指定寬度的域設置填充字符的值。爲了用星號填充數值列,我們可以將上例中的for循環修改如下:
for(int i=0;i<4;i++)    
    {
    cout.width(10);
    cout.fill("*");
    cout<<s[i]<<endl;
    }
其輸出結果如下:
 *******1.23
 ******35.26
 *****653.7
 ****4358.24
如果要爲同一行中輸出的不同數據項分別指定寬度,可以使用setw操縱符.
例 使用setw操縱符指定寬度
#i nclude<iostream.h> 
#i nclude<iomanip.h> 
void main() 
{
 double s[]={1,23,35.36,653.7,4358.24};
 char *names[]={"Zoot","Jimmy","Al","Stan"};
 for (int i=0;i<4;i++)
  cout<<setw(6)<<names[i]<<setw(10)<<s[i]<<endl; 
}
width成員函數在iostream.h中說明了,如果帶參量使用setw或任何其他操縱符,就必須包括iomanip.h。在輸出中,字符串輸出在寬度爲6的域中,整數輸出在寬度爲10的域中,運行結果如下:
Zoot      1.23
Jimmy     35.36
    Al    653.7 
  Stan   4358.24
    setw和width都不截斷數值。如果數值位超過了指定寬度,則顯示全部值,當然還要遵守該流的精度設置。setw和width僅影響緊隨其後的域,在一個域輸出完後域寬度恢復成它的缺省值(必要的寬度)。但其他流格式選項保持有效直到發生改變。

   2.對齊方式
輸出流缺省爲右對齊文本,爲了在前面的例子中左對齊姓名和右對齊數值,要將程序修改如下:
例   設置對齊方式
#i nclude<iostream.h> 
#i nclude<iomanip.h> 
void main() 
{
 double s[]={1.23,35.36,653.7,4358.24};
 char *names[]={"Zoot","Jimmy","Al","Stan"};
 for (int i=0;i<4;i++)
  cout<<setiosflags(ios::left)
   <<setw(6)<<names[i]
   <<resetiosflags(ios::left) 
   <<setw(10)<<s[i]<<endl; 
}
其輸出結果如下:
Zoot       1.23
Jimmy      35.36
Al          653.7 
Stan      4358.24
    這個程序中,是通過使用帶參數的setiosflags操縱符來設置左對齊,參數是los::left枚舉器。該枚舉器定義在ios類中,因此引用時必須包括ios::前綴。這裏需要用resetiosflags操縱符關閉左對齊標誌。setiosflags不同於width和setw,它的影響是持久的,直到用resetiosflags重新恢復缺省值時爲止。
    setiosflags的參數是該流的格式標誌值,這個值由如下位掩碼(ios枚舉器)指定,並可用位或OR(|)運算符進行組合:
    ios::skipws  在輸人中跳過空白。    
    ios::left  左對齊值,用填充字符填充右邊。
    ios::right  右對齊值;用填充字符填充左邊(缺省對齊方式)。
    ios::internal  在指定任何引導標記或基之後增加填充字符。
    ios::dec  以基10(十進制)格式化數值(缺省進制)。
    ios::oct  以基8(八進制)格式化數值。
    ios::hex  以基16(十六進制)格式化數值。
    ios::showbase  以C++編譯器能讀的格式顯示數值常量。
    ios::showpoint  對浮點數值顯示小數點和尾部的0。
    ios::uppercase  對於十六進制數值顯示大寫字母A到F,對於科學格式顯示大寫字母E。
    ios::showpos  對於正數顯示正號(+)。
    ios::scientific  以科學格式顯示浮點數值。
    ios::fixed  以定點格式顯示浮點數值。
    ios::unitbuf  導致在每次插入之後ostream::osfx刷新該流。缺省地,cerr是緩衝的單元。
    ios::stdio  導致在每次插入之後ostream::osfx刷新該流的stdout和stderr。
    3.精度
    浮點數輸出精度的缺省值是6,例如,數3466.9768顯示爲3466.98。爲了改變精度,可以使用setprecision操縱符,該操縱符有兩個標誌,ios::fixed和los::scientific。如果設置了ios::fixed,該數輸出爲3466.976800;如果設置了ios::scientific,該數輸出爲 3.4669773+003。爲了以1位有效數字顯示浮點數,將前述程序修改如下:
例   控制輸出精度 
#i nclude<iostream.h> 
#i nclude<iomanip.h> 
void main() 
{
 double s[]={1.23,35.36,653.7,4358.24};
 char* names[]={"Zoot","Jimmy","Al","Stan"};
 for(int i=0;i<4;i++)
  cout<<setiosflags(ios::left)
  <<setw(6)<<names[i]
  <<resetiosflags(ios::left)
  <<setw(10)<<setprecision(1)<<s[i]<<endl; 
}
該程序的輸出結果如下:
Zoot         1
Jimmy      4e+001
Al          7e+002 
Stan        5e+003
如果要刪除科學標記,需要在for循環之前插入語句: cout<<setiosflags(ios::fixed);如果要採用定點標記,該程序用一個小數位輸出的結果如下:
Zoot        1.2
Jimmy         35.4
Al            653.7 
Stan        4358.2
如果改變ios::fixed爲ios::scientific,該程序的輸出結果爲:
Zoot      1.2e+000
Jimmy      3.5e+001
Al          6.5e+002 
Stan        4.4e+003
    同樣,該程序在小數點後輸出了一位數字,這表明如果設置了ios::fixed或 ios::scientific,則精度值確定了小數點之後的小數位數。如果都未設置,則精度值確定了總的有效位數。可以用resetiosflags操縱符清除這些標誌。
    4.進制
dec、oct和hex操縱符設置輸入和輸出的缺省進制,例如,若將hex操縱符插入到輸出流中,則以十六進制格式輸出。如果ios::uppercase(缺省)標誌已清除,該數值以a到f的數字顯示;否則,以大寫方式顯示。缺省的進制是dec(十進制)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章