1. 程式人生 > >第17章 輸入、輸出和檔案

第17章 輸入、輸出和檔案

本章內容包括:

  • C++角度的輸入和輸出.
  • iostream類系列
  • 重定向
  • ostream類方法
  • 格式化輸出
  • istream類方法
  • 流狀態
  • 檔案I/O
  • 使用ifstream類從檔案輸入
  • 使用ofstream類輸出到檔案
  • 使用fstream類進行檔案輸入和輸出
  • 命令列處理
  • 二進位制檔案
  • 隨機檔案訪問
  • 核心格式化

用於檔案輸入和輸出的C++工具都是基於cin和cout所基於的基本類定義.因此本章以對控制檯I/O(鍵盤和螢幕)的討論為跳板,來研究檔案I/O.

17.1 C++輸入和輸出概述

  • C++依賴於C++的I/O解決方案,而不是C語言的I/O解決方案,前者是在標頭檔案iostream(以前為iostream.h)和fstream(以前為fstream.h)中定義一組類.這個類庫不是正式語言定義的組成部分(cin和istream不是關鍵字);

17.1.1 流和緩衝區

  • C++程式把輸入和輸出看作位元組流.流充當了程式和流源或流目標之間的橋樑.
  • C++程式只是檢查位元組流,而不需要知道位元組來自何方.同理,通過使用流,C++程式處理輸出的方式將獨立於其去向.因此管理輸入包含兩步: 
    • 將流與輸入去向的程式關聯起來
    • 將流與檔案連線起來.
  • 通常,通過使用緩衝區可以更高效得處理輸入和輸出.
  • 鍵盤輸入每次提供一個字元,因此在這種情況下,程式無需緩衝區來幫助匹配不同的資料傳輸速率.然而,對鍵盤輸入進行緩衝可以讓使用者在將輸入傳輸給程式之前返回並更正.C++程式通常在使用者按下回車鍵時重新整理輸入緩衝區.

17.1.2 流、緩衝區和iostream檔案

  • 通過使用typedef工具,C++使得這些模板char具體化能夠模仿傳統的非模板I/O實現.
  • 重定義I/O:ISO/ANSI標準C++98對I/O做了兩方面的修訂.首先是從ostream.h到ostream的變化,用ostream將類放在std名稱空間中.其次I/O類被重新編寫.為成為國際語言,C++bixu能夠處理需要16位的國際字符集或更寬的字元型別.因此,該語言在傳統的8位char(“窄”)型別的基礎上添加了wchar_t(“寬”)字元型別;而C++11tianjia了型別char16_t和char32_t.每種型別都需要有自己的I/O工具.標準委員會並沒有開發兩套(現在為4套)獨立的類,而是開發了1套I/O類模板,其中包括basic_istream<charT,traits<charT>>和basic_ostream<charT,traits<charT>>.traits<charT>模板是一個模板類,為字元型別定義了具體特性,如如何比較字元是否相等以及字元的EOF值等.該C++11標準提供了I/O的char和wchar_t具體化.例如,istream和ostream都是char具體化的typedef.同樣,wistream和wostream都是wchar_t具體化.例如,wcout物件用於輸出寬字元流.標頭檔案ostream中包含了這些定義.ios基類彙總的一些獨立於型別的資訊被移動到新的ios_base類中,這包括各種格式化常量,例如ios:fixed(現在為ios_base::fixed).另外,ios_base還包含了一些老式ios中沒有的選項.
  • cout << “Bjarne free”; 這個語句通過指向的streambuf物件將字串”Bjarne free”中的字元放到cout管理的緩衝區中;ostream類定義了上述語句中使用的operator<<()函式,ostream類還支援cout資料成員以及其他大量的類方法.另外,C++注意到,來自緩衝區的輸出被引導到標準輸出(通常是顯示器,由作業系統提供).總之,流的一端與程式相連,另一端與標準輸出相連,cout物件憑藉streambuf物件的幫助,管理著六種的位元組流.

17.1.3 重定向

  • 這個工具使得能夠改變標準輸入和標準輸出.通過輸入重定向(<)和輸出重定向(>)
  • 換句話說,作業系統改變了輸入流的流入端連線,而流出端仍然與程式相連.

17.2 使用cout進行輸出 
17.2.1 過載的<<運算子

  • 在C++中,與C一樣,<<運算子的預設含義是按位左移運算子.但ostream類重新定義了<<運算子,方法是將其過載為輸出.在這種情況下,<<叫做插入運算子.
  • 1.輸出和指標 
    • ostream類還未下面的指標型別定義了插入運算子函式: 
      • const signed char *;
      • const unsigned char *;
      • const char *;
      • void *;
    • 方法使用字串中的終止空字元來確定何時停止顯示字元.
  • 2.拼接輸出 
    • 插入運算子的所有化身的返回型別都是ostream&.也就是說,原型的格式如下:ostream & operator<<(type);
    • 函式定義指出,引用將指向用於呼叫該運算子的物件.換句話說,運算子函式的返回值為呼叫運算子的物件.

17.2.2 其他ostream方法

  • ostream類還提供了put()方法和write()方法,前者用於顯示字元,後者用於顯示字串.
  • 一些老式編譯器錯誤地為char,unsigned char和signed char 3種引數型別過載了put().這使得將int引數用於put()時具有二義性,因為int可被轉換為這3種類型中的任何一種.
  • 程式清單17.1 write.cpp 
    • write()方法並不會在遇到空字元時自動停止列印字元,而只是打印製定數目的字元,即使超出了字串的邊界!

17.2.3 重新整理輸出緩衝區

  • 如果程式使用cout將位元組傳送給標準輸出,情況如何?由於ostream類對cout物件處理的輸出進行緩衝,所以輸出不會立即傳送到目標地址,而是被儲存在緩衝區中,知道緩衝區填滿.然後,程式將舒心flush緩衝區,把內容傳送出去,並清空緩衝區,以儲存新的資料.通常,緩衝區為512位元組或其整數倍.
  • 可以用更為方便的插入表示法來成功的進行重新整理.

17.2.4 用cout進行格式化

  • ostream插入運算子將值轉換為文字格式.
  • 注意:並非所有的編譯器都能生成符合當前C++標準格式的輸出.另外,當前標準允許區域性變化.例如,歐洲實現可能遵循歐洲人的風格:使用逗號而不是句點來表示小數點.也就是說,2.54將被寫成2,54.區域庫(標頭檔案locale)提供了用特定的風格影響imbuing輸入或輸出流的機制,所以同一個編譯器能夠提供多個區域選項.本章使用美國格式.
  • 程式清單17.2 defaults.cpp 
    • 注意,1.200末尾的0沒有顯示出來,但末尾0的浮點值後面將有6個空格.
  • 1.修改顯示時使用的計數系統 
    • ostream類是從ios類派生而來的,而後者是從ios_base類派生而來的.ios_base類儲存了描述格式狀態的資訊.
    • 注意:ios_base類中的成員和方法以前位於ios類中.現在,ios_base是ios的基類.在新系統中,ios是包含char和wchar_t具體化的模板,而ios_base包含了非模板特性.
    • 程式清單17.3 manip.cpp
  • 2.調整欄位寬度 
    • 可以使用width成員函式將長度不同的數字放到寬度相同的欄位中.
    • width()方法隻影響將顯示的下一個專案,然後欄位寬度將恢復為預設值.
    • C++永遠不會截短資料,因此如果檢視在寬度為2的欄位中列印一個7位值,C++將增寬欄位,以容納該資料(在有些語言中,如果資料長度與欄位寬度不匹配,將用星號填充欄位.C/C++的原則是:顯示所有的資料比保持列的整潔更重要.C++視內容重於形式).
    • 程式清單17.4 width.cpp
  • 3.填充字元 
    • 在預設情況下,cout用空格填充欄位中未被使用的部分,可以用fill()成員函式來改變填充字元.
    • 程式清單17.5 fill.cpp 
      • 注意,與欄位寬度不同的是,新的填充字元將一直有效,直到更改它為止.
  • 4.設定浮點數的顯示精度 
    • 浮點數精度的含義取決於輸出模式.在預設模式下,它值得是顯示的總位數.
    • 已經知道,C++的預設精度為6位(但末尾的0將不顯示)
    • precision()成員函式使得能夠選擇其他值.
    • 和width()的情況不同,但與fill()類似,新的精度設定將一直有效,直到被重新設定.
    • 程式清單17.6 precise.cpp
  • 5.列印末尾的0和小數點 
    • iostream系列類沒有提供專門用於完成這項任務的函式,但ios_base類提供了一個setf()函式(用於set標記),能夠控制多種格式化特性.
    • 程式清單17.7 showpt.cpp
  • 6.再談setf() 
    • setf()函式有兩個原型. 
      • fmtflags setf(fmtflags); 
        • 其中,fmtflags是bitmask型別的typedef名,用於儲存格式標記.該名稱是在ios_base類中定義的.
        • 注意:bitmask型別是一種用來儲存各個位值的型別.它可以是整型,列舉,也可以是STL bitset容器.這裡的主要思想是,每一位都是可以單獨訪問的,都有自己的含義.iostream軟體包使用bitmask來儲存狀態資訊.
        • 使用它們時,必須加上作用域解析運算子.也就是說,應使用ios_base::uppercase,而不是uppercase.如果不想使用using編譯指令或using宣告,可以使用作用域運算子來指出這些名稱位於名稱空間std中.修改將一直有效,直到被覆蓋為止.
        • 程式清單17.8 setf.cpp 
          • 注意,僅當基數為10時才使用加號.C++將十六進位制和八進位制都視為無符號的,因此對它們,無需使用符號(然而,有些C++實現可能仍然會顯示加號).
      • fmtflags setf(fmtflags , fmtflags); 
        • 這種過載格式用於設定由多位控制的格式選項.
        • 遺憾的是,C++沒有提供自對齊模式
        • 程式清單17.9 setf2.cpp
    • 呼叫setf()的效果可以通過unsetf()消除.後者的原型是:void unsetf(fmtflags mask);其中,mask是位模式.mask中所有的位都設定為1,將使得對應的位被複位.也就是說,setf()將位位置為1,unsetf()將位恢復為0.
    • 系統的工作原理如下:僅當只有定點位被設定時使用定點表示法;僅當只有科學位被設定時使用科學表示法;對於其他組合,如沒有位被設定或兩位都被設定時,將使用預設模式.
  • 7.標準控制符
  • 8.標頭檔案iomanip 
    • 3個最常用的控制符分別是setprecision(),setfill()和setw(),它們分別用來設定精度,填充字元和欄位寬度.
    • 程式清單17.10 iomanip.cpp

17.3 使用cin進行輸入

  • cin解釋輸入的方式取決於value_holder的資料型別.

17.3.1 cin>>如何檢查輸入

  • 不同版本的抽取運算子檢視輸入流的方法是相同的.
  • 程式清單17.11 check_it.cpp

17.3.2 流狀態

  • 1.設定狀態 
    • 為什麼需要重新設定流狀態呢?對於程式設計師來說,最常見的理由是,在輸入不匹配或到達檔案尾時,需要使用不帶引數的clear()重新開啟輸入.是否有意義,取決於程式要執行的任務.
  • 2.I/O和異常 
    • 假設某個輸入函式設定了eofbit,這是否會導致異常被引發呢?在預設情況下,答案是否定的.但可以使用exceptions()方法來控制異常如何被處理.
    • 程式清單17.12 cinexcp.cpp
  • 3.流狀態的影響

17.3.3 其他istream類方法

  • 1.單字元輸入 
    • (1).成員函式get(char &)
  • 2.採用哪種單字元輸入形式
  • 3.字串輸入:getline(),get()和ignore() 
    • 程式清單17.13 get_fun.cpp
  • 4.意外字串輸入

17.3.4 其他istream方法

  • 程式清單17.14 peeker.cpp
  • 程式清單17.15 truncate.cpp

17.4 檔案輸入和輸出 
17.4.1 簡單的檔案I/O

  • 警告:以預設模式開啟檔案進行輸出將自動把檔案的長度截短為零,這相當於刪除已有的內容.
  • 讀取檔案的要求與寫入檔案相似: 
    • 建立一個ifstream物件來管理輸入流
    • 將該物件與特定的檔案關聯起來
    • 以使用cin的方式使用該物件
  • 當輸入和輸出流物件過期(如程式終止)時,到檔案的連線將自動關閉.另外,也可以使用close()方式來顯式地關閉到檔案的連線.關閉這樣的連線並不會刪除流,而只是斷開流到檔案的連線.然而,流管理裝置仍被保留.
  • 程式清單17.16 fileio.cpp

17.4.2 流狀態檢查和is_open()

  • 警告:以前,檢查檔案是否成功開啟的常見方式如下:
if(fin.fail()) ... //failed to open
if(!fin.good()) ... //failed to open
if(!fin) ... //failed to open
  • fin物件被用於測試條件中時,如果fin.good()為false,將被轉換為false;否則將被轉換成true.因此上面三種方式等價.然而,這些測試無法檢測到這樣一種情形:試圖以不適合的檔案模組開啟檔案時失敗.方法is_open()能夠檢測到這種錯誤以及good()能夠檢測到的錯誤.然而,老式C++實現沒有is_open();

17.4.3 開啟多個檔案

  • 在這種情況下,可以開啟一個流,並將它依次關聯到各個檔案.

17.4.4 命令列處理技術

  • C++有一種讓在命令列環境中執行的程式能夠訪問命令列引數的機制,方法是使用下面的main()函式:int main(int argc,char *argv[])
  • 程式清單17.17 count.cpp注意: 
    • 有些C++實現要求在該程式末尾使用fin.clear(),有些則不要求,這取決於將檔案與ifstream物件關聯起來時,是否自動重置流轉太.使用fin.clear()是無害的,即使在不必使用它的時候使用.

17.4.5 檔案模式

  • ios_base類定義了一個openmode型別,用於表示模式;與fmtflags和iostate型別一樣,它也是一種bitmask型別(以前,其型別為int).可以選擇ios_base類中定義的多個常量來指定模式.
  • 1.追加檔案 
    • 注意:在早起,檔案I/O可能是C++最不標準的部分,很多老式編譯器都不遵守當前的標準.例如,有些編譯器使用諸如nocreate等模式,而這些模式不是當前標準的組成部分.另外,只有一部分編譯器要求在第二次開啟同一個檔案進行讀取之前呼叫fin.clear().
    • 程式清單17.18 append.cpp
  • 2.二進位制檔案 
    • 二進位制格式對於數字來說比較精確,因為它儲存的是值的內部表示,因此不會有轉換誤差或舍入誤差.以二進位制格式儲存資料的熟讀更快,因為不需要轉換,並可以大塊地快出資料.二進位制格式通常佔用的空間較小,這取決於資料的特徵.
    • 二進位制檔案和文字檔案:使用二進位制檔案模式時,程式將資料從記憶體傳輸給檔案(反之亦然)時,將不會發生任何隱藏的轉換,而預設的文字模式並非如此.例如,對於Windows文字檔案,它們使用兩個字元的組合(回車和換行)表示換行符;Macintosh文字檔案使用回車來表示換行符;而UNIX和Linux檔案使用換行(linefeed)來表示換行符.C++是從UNIX系統上發展而來的,因此也使用換行(linefeed)來表示換行符;為增加可一致性,Windows C++程式在寫文字模式檔案時,自動將C++換行符轉換為回車和換行;Macintosh C++程式在寫檔案時,將換行符轉換為回車.在讀取文字檔案時,這些程式將本地換行符轉換為C++格式.對於二進位制資料,文字格式會引起問題,因此double值中間的位元組可能與換行符的ASCII碼有相同的位模式.另外,在檔案尾的檢測方式也有區別.因此以二進位制格式儲存資料時,應使用二進位制檔案模式(UNIX系統只有一種檔案模式,因此對於它來說,二進位制模式和文字模式是一樣的).
    • 提示:read()和write()成員函式的功能是相反的.請用read()來恢復用write()寫入的資料.
    • 注意:雖然二進位制檔案概念是ANSI C的組成部分,但一些C和C++實現並沒有提供對二進位制檔案模式的支援.原因在於:有些系統只有一種檔案型別,因此可以將二進位制操作(如read()和write())用於標準檔案格式.因此,如果實現認為ios_base::binary是非法常量,只要刪除它即可.如果實現不支援fixed和right控制符,則可以使用cout.setf(ios_base::fixed,ios_base::floatfield)和cout.setf(ios_base::right,ios_base::adjustfield).另外,也可能必須用ios替換ios_base.其他編譯器(特別是老式編譯器)可能還有其他特徵.
    • 程式清單17.19 binary.cpp

17.4.6 隨機存取

  • 隨機存取指的是直接移動(不是依次移動)到檔案的任何位置.隨機存取常被用於資料庫檔案,程式維護一個獨立的索引檔案,該檔案指出資料在主資料檔案中的位置.這樣,程式便可以直接跳到這個位置,讀取(還可能修改)其中的資料.
  • 如果檔案由長度相同的記錄組成,這種方法實現起來最簡單.
  • 型別升級:在C++早起,seekg()方法比較簡單.Streamoff和streampos型別是一些標準整型(如long)的typedef.但為建立可移植標準,必須處理這樣的現實情況:對於有些檔案系統,整數引數無法提供足夠的資訊,因此streamoff和streampos允許是結構或類型別,條件是它們允許一些基本的操作,如使用整數值作為初始值等.隨後,老版本的istream類被basic_istream模板取代,streampos和streamoff被basic_istream模板取代.然而,streampos和streamoff繼續存在,作為pos_type和off_type的char的具體化.同樣,如果將seekg()用於wistream物件,可以使用wstreampos和wstreamoff型別.
  • 注意:實現越舊,與C++標準相沖突的可能性越大.一些系統不能識別二進位制標記,fixed和right控制符以及ios_base.
  • 程式清單17.20 random.cpp
// random.cpp -- random access to a binary file
#include <iostream>     // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib>      // (or stdlib.h) for exit()
const int LIM = 20;
struct planet
{
    char name[LIM];      // name of planet
    double population;  // its population
    double g;           // its acceleration of gravity
};
const char * file = "planets.dat";  // ASSUMED TO EXIST (binary.cpp example)
inline void eatline() { while (std::cin.get() != '\n') continue; }
int main()
{
    using namespace std;
    planet pl;
    cout << fixed;
// show initial contents
    fstream finout;     // read and write streams
    finout.open(file, 
           ios_base::in | ios_base::out | ios_base::binary);
    //NOTE: Some Unix systems require omitting | ios::binary
    int ct = 0;
    if (finout.is_open())
    {
        finout.seekg(0);    // go to beginning
        cout << "Here are the current contents of the "
             << file << " file:\n";
        while (finout.read((char *) &pl, sizeof pl))
        {
            cout << ct++ << ": " << setw(LIM) << pl.name << ": "
                 << setprecision(0) << setw(12) << pl.population
                 << setprecision(2) << setw(6) << pl.g << endl;
        }
        if (finout.eof())
            finout.clear(); // clear eof flag
        else
        {
            cerr << "Error in reading " << file << ".\n";
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        cerr << file << " could not be opened -- bye.\n";
        exit(EXIT_FAILURE);
    }
// change a record
    cout << "Enter the record number you wish to change: ";
    long rec;
    cin >> rec;
    eatline();              // get rid of newline
    if (rec < 0 || rec >= ct)
    {
        cerr << "Invalid record number -- bye\n";
        exit(EXIT_FAILURE);
    }
    streampos place = rec * sizeof pl;  // convert to streampos type
    finout.seekg(place);    // random access
    if (finout.fail())
    {
        cerr << "Error on attempted seek\n";
        exit(EXIT_FAILURE);
    }
    finout.read((char *) &pl, sizeof pl);
    cout << "Your selection:\n";
    cout << rec << ": " << setw(LIM) << pl.name << ": "
         << setprecision(0) << setw(12) << pl.population
         << setprecision(2) << setw(6) << pl.g << endl;
    if (finout.eof())
        finout.clear();     // clear eof flag
    cout << "Enter planet name: ";
    cin.get(pl.name, LIM);
    eatline();
    cout << "Enter planetary population: ";
    cin >> pl.population;
    cout << "Enter planet's acceleration of gravity: ";
    cin >> pl.g;
    finout.seekp(place);    // go back
    finout.write((char *) &pl, sizeof pl) << flush;
    if (finout.fail())
    {
        cerr << "Error on attempted write\n";
        exit(EXIT_FAILURE);
    }
// show revised file
    ct = 0;
    finout.seekg(0);            // go to beginning of file
    cout << "Here are the new contents of the " << file
         << " file:\n";
    while (finout.read((char *) &pl, sizeof pl))
    {
        cout << ct++ << ": " << setw(LIM) << pl.name << ": "
             << setprecision(0) << setw(12) << pl.population
             << setprecision(2) << setw(6) << pl.g << endl;
    }
    finout.close();
    cout << "Done.\n";
// keeping output window open
    // cin.clear();
    // eatline();
    // cin.get();
    return 0; 
}
  • 使用臨時檔案:開發應用程式時,經常需要使用臨時檔案,這種檔案的存在是短暫的,必須受程式控制.您是否考慮過,在C++中如何使用臨時檔案呢?建立臨時檔案,複製另一個檔案的內容並刪除檔案棋士都很簡單.首先,需要為臨時檔案制定一個命名方案,但如何確保每個檔案都被制定了獨一無二的檔名呢?cstdio中宣告的tmpnam()標準函式可以幫助您.char* tmpnam(char* pszName);tmpnam()函式建立一個臨時檔名,將它放在pszName指向的C-風格字串中.常量L_tmpnam和TMP_MAX(二者都是在cstdio中定義的)限制了檔名包含的字元數以及在確保當前目錄中不生成重複檔名的情況下tmpnam()可被呼叫的最多次數.

17.5 核心格式化

  • string的sstream族支援取代了char陣列的strstream.h族支援.
  • 程式清單17.21 strout.cpp
  • 程式清單17.22 strin.cpp
  • 總之,istringstream和ostringstream類使得能夠使用istream和ostream類的方法來管理儲存在字串中的字元資料.

17.6 總結

  • 流是進出程式的位元組流.緩衝區是記憶體中的臨時儲存區域,是程式與檔案或其他I/O裝置之間的橋樑.資訊在緩衝區和檔案之間傳輸時,將使用裝置(如磁碟驅動器)處理效率最高報的尺寸以大塊資料的方式進行傳輸.資訊在緩衝區和程式之間傳輸時,是逐位元組傳輸的,這種方式對於程式中的處理操作更為方便.C++通過講一個被緩衝流同程式及其輸入源相連來處理輸入.同樣,C++也通過將一個被緩衝流與程式及其輸出目標相連來處理輸出.iostream和fstream檔案構成了I/O類庫,該類庫定義了大量用於管理流的類.包含了iostream檔案的C++程式將自動開啟8個流,並使用8個物件管理它們.cin物件管理標準輸入流,後者預設與標準輸入裝置(通常為鍵盤)相連;cout物件管理標準輸出流,後者預設與標準輸出裝置(通常為顯示器)相連;cerr和clog物件管理與標準錯誤裝置(通常為顯示器)相連的未被緩衝的流和被緩衝的流.這4個物件有都有用於寬字元的副本,它們是wcin,wcout,wcerr和wclog.
  • I/O類庫提供了大量有用的方法.istream類定義了多個版本的抽取運算子(>>),用於識別所有基本的C++型別,並將字元輸入轉換為這些型別.get()方法族和getline()方法為檔子符輸入和字串輸入提供了進一步的支援.同樣,ostream類定義了多個版本的輸入運算子(<<),用於識別所有的C++基本型別,並將他們轉換為相應的字元輸出.put()方法對單字元輸出提供了進一步的支援.sistream和sostream類對款字元提供了類似的支援.
  • 使用ios_base類方法以及檔案iostream和iomanip中定義的控制符(可與插入運算子拼接的函式),可以控制程式如何格式化輸出.這些方法和控制符是的能夠控制計數系統,欄位寬度,小數位數,顯示浮點變數時採用的計數系統以及其他元素.
  • fstream檔案提供了將iostream方法擴充套件到檔案I/O的類定義.ifstream類侍從istream類派生而來的.通過將ifstream物件與檔案關聯起來,可以使用所有的istream方法讀取檔案.同樣,通過將ofstream物件與檔案關聯起來,可以使用ostream方法來寫檔案;通過將 fstream物件與檔案關聯起來,可以將輸入和輸出方法用於檔案.
  • 要將檔案與流關聯起來,可以在初始化檔案流物件時提供檔名,也可以先建立一個檔案流物件,然後用open()方法將這個流與檔案關聯起來.close()方法終止流與檔案之間的連線.類建構函式和open()方法接收可選的第二個引數,該引數提供檔案模式.檔案模式決定檔案是否被讀和/或寫,開啟檔案以便寫入時是否截短檔案,試圖開啟不存在的檔案時是否會導致錯誤,是使用二進位制模式還是文字模式等.
  • 文字檔案以字元格式儲存所有的資訊,例如,數字值將被轉換為字元表示.常規的插入和抽取運算子以及get()和geline()都支援這種模式.二進位制檔案使用計算機內部使用的二進位制表示來儲存資訊.與文字檔案相比,二進位制檔案儲存資料(尤其是浮點值)更為精確,簡潔,但可移植性較差.read()和write()方法都支援二進位制輸入和輸出
  • seekg()和seekp()函式提供對檔案的隨機存取.這些類方法使得能夠將檔案指標放置到相對於檔案開頭,檔案尾和當前位置的某個位置.tellg()和tellp()方法報告當前的檔案位置.
  • sstream標頭檔案定義了istringstream和ostringstream類,這些類使得能夠使用istream和ostream方法來抽取字串中的資訊,並對要放入到字串彙總的資訊進行格式化.

17.7 複習題 
17.8 程式設計練習

本章原始碼下載地址