【轉載】C++文件操作(一)

1. 文件的概念

    以前進行的輸入輸出操作都是在鍵盤和顯示器上進行的,通過鍵盤向程序輸入待處理的數據,通過顯示器輸出程序運行過程中需要告訴用戶的信息。鍵盤是C++系統中的標準輸入設備,用cin流表示,顯示器是C++系統中的標準輸出設備,用cout流表示。

    數據的輸入和輸出除了可以在鍵盤和顯示器上進行之外,還可以在磁盤上進行。磁盤是外部存儲器,它能夠永久保存信息,並能夠被重新讀寫和攜帶使用。所以若用戶需要把信息保存起來,以便下次使用,則必須把它存儲到外存磁盤上。

    在 磁盤上保存的信息是按文件的形式組織的,每個文件都對應一個文件名,並且屬於某個物理盤或邏輯盤的目錄層次結構中一個確定的目錄之下。一個文件名由文件主 名和擴展名兩部分組成,它們之間用圓點(即小數點)分開,擴展名可以省略,當省略時也要省略掉前面的圓點。文件主名是由用戶命名的一個有效的C++標識 符,爲了同其他軟件系統兼容,一般讓文件主名爲不超過8個有效字符的標識符,同時爲了便於記憶和使用,最好使文件主名的含義與所存的文件內容相一致。文件 擴展名也是由用戶命名的、1至3個字符組成的、有效的C++標識符,通常用它來區分文件的類型。如在C++系統中,用擴展名h表示頭文件,用擴展名cpp 表示程序文件,用obj表示程序文件被編譯後生成的目標文件,用exe表示連接整個程序中所有目標文件後生成的可執行文件。對於用戶建立的用於保存數據的 文件,通常用dat表示擴展名,若它是由字符構成的文本文件則也用txt作爲擴展名,若它是由字節構成的、能夠進行隨機存取的內部格式文件則可用ran表 示擴展名。

    在 C++程序中使用的保存數據的文件按存儲格式分爲兩種類型,一種爲字符格式文件,簡稱字符文件,另一種爲內部格式文件,簡稱字節文件。字符文件又稱 ASCII碼文件或文本文件,字節文件又稱二進制文件。在字符文件中,每個字節單元的內容爲字符的ASCII碼,被讀出後能夠直接送到顯示器或打印機上顯 示或打印出對應的字符,供人們直接閱讀。在字節文件中,文件內容是數據的內部表示,是從內存中直接複製過來的。當然對於字符信息,數據的內部表示就是 ASCII碼錶示,所以在字符文件和在字節文件中保存的字符信息沒有差別,但對於數值信息,數據的內部表示和ASCII碼錶示截然不同,所以在字符文件和 在字節文件中保存的數值信息也截然不同。如對於一個短整型數1069,它的內部表示佔有兩個字節,對應的十六進制編碼爲04 2D,其中04爲高字節值,2D爲低字節值;若用ASCII碼錶示則爲四個字節,每個字節依次爲1069中每個字符的ASCII碼,對應的十六進制編碼爲 31 30 36 39。當從內存向字符文件輸出數值數據時需要自動轉換成它的ASCII碼錶示,相反,當從字符文件向內存輸入數值數據時也需要自動將它轉換爲內部表示,而 對於字節文件的輸入輸出則不需要轉換,僅是內外存信息的直接拷貝,顯然比字符文件的輸入輸出要快得多。所以當建立的文件主要是爲了進行數據處理時,則適宜 建立成字節文件,若主要是爲了輸出到顯示器或打印機供人們閱讀,或者是爲了供其他軟件使用時,則適宜建立成字符文件。另外,當向字符文件輸出一個換行符/n時,則將被看作爲輸出了回車/r和換行/n兩個字符;相反,當從字符文件中讀取回車和換行兩個連續字符時,也被看作爲一個換行符讀取。

    C++程序文件,利用其他各種語言編寫的程序文件,用戶建立的各種文本文件,各種軟件系統中的幫助文件等,因都是ASCII碼文件,所以都可以在C++中作爲字符文件使用。

    C++ 系統把各種外部設備也看作爲相應的文件。如把標準輸入設備鍵盤和標準輸出設備顯示器看作爲標準輸入輸出文件,其文件名(又稱設備名)爲con,當向它輸出 信息時就是輸出到顯示器,當從它輸入信息時就是從鍵盤輸入。標準輸入輸出文件con對應兩個系統預定義的流,即標準輸入流cin和標準輸出流cout,分 別用於鍵盤輸入和顯示器輸出。由於鍵盤和顯示器都屬於字符設備,所以它們都是字符格式文件。以後對字符文件所介紹的訪問操作也同樣適應於鍵盤和顯示器,而 以前介紹的對鍵盤(cin)和顯示器(cout)的訪問操作也同樣適應於所有字符文件。

    無 論是字符文件還是字節文件,在訪問它之前都要定義一個文件流類的對象,並用該對象打開它,以後對該對象的訪問操作就是對被它打開文件的訪問操作。對文件操 作結束後,再用該對象關閉它。對文件的訪問操作包括輸入和輸出兩種操作,輸入操作是指從外部文件向內存變量輸入數據,實際上是系統先把文件內容讀入到該文 件的內存緩衝區中,然後再從內存緩衝區中取出數據並賦給相應的內存變量,用於輸入操作的文件稱爲輸入文件。對文件的輸出操作是指把內存變量或表達式的值寫 入到外部文件中,實際上是先寫入到該文件的內存緩衝區中,待緩衝區被寫滿後,再由系統一次寫入到外部文件中,用於輸出操作的文件稱爲輸出文件。

    一 個文件中保存的內容是按字節從數值0開始順序編址的,文件開始位置的字節地址爲0,文件內容的最後一個字節的地址爲n-1(假定文件長度爲n,即文件中所 包含的字節數),文件最後存放的文件結束符的地址爲n,它也是該文件的長度值。當一個文件爲空時,其開始位置和最後位置(即文件結束符位置)同爲0地址位 置。

    對 於每個打開的文件,都存在着一個文件指針,初始指向一個隱含的位置,該位置由具體打開方式決定。每次對文件寫入或讀出信息都是從當前文件指針所指的位置開 始的,當寫入或讀出若干個字節後,文件指針就後移相應多個字節。當文件指針移動到最後,讀出的是文件結束符時,則將使流對象調用eof()成員函數返回非 0值(通常爲1),當然讀出的是文件內容時將返回0。文件結束符佔有一個字節,其值爲-1,在ios類中把EOF常量定義爲-1。若利用字符變量依次讀取 字符文件中的每個字符,當讀取到的字符等於文件結束符EOF時則表示文件訪問結束。

    要 在程序中使用文件時,首先要在開始包含#include<fstream.h>命令。由它提供的輸入文件流類ifstream、輸出文件流類 ofstream和輸入輸出文件流類fstream定義用戶所需要的文件流對象,然後利用該對象調用相應類中的open成員函數,按照一定的打開方式打開 一個文件。文件被打開後,就可以通過流對象訪問它了,訪問結束後再通過流對象關閉它。

    每個文件流類都有一個open成員函數,並且具有完全相同的聲明格式,具體聲明格式爲:

        void open(const char* fname, int mode);

    其 中fname參數用於指向要打開文件的文件名字符串,該字符串內可以帶有盤符和路徑名,若省略盤符和路徑名則隱含爲當前盤和當前路徑,mode參數用於指 定打開文件的方式,對應的實參是ios類中定義的open_mode枚舉類型中的枚舉常量,或由這些枚舉常量構成的按位或表達式。

    open_mode枚舉類型中的每個枚舉常量的含義如下:

    ios::in          //使文件只用於數據輸入,即從中讀取數據。

    ios::out         //使文件只用於數據輸出,即向它寫入數據。

ios::ate         //使文件指針移至文件尾,即最後位置。

    ios::app         //使文件指針移至文件尾,並只允許向文件尾輸出(即追加)數據。

    ios::trunc       //若打開的文件存在,則清除其全部內容,使之變爲空文件。

    ios::nocreate    //若打開的文件不存在則不建立它,返回打開失敗信息。

    ios::noreplace   //若打開的文件存在則返回打開失敗信息。

    ios::binary      //規定打開的爲二進制文件,否則打開的爲字符文件。

下面對文件的打開方式作幾點說明:

    (1) 文件的打開方式可以爲上述的一個枚舉常量,也可以爲多個枚舉常量構成的按位或表達式。如:

    ios::in | ios::nocreate   //規定打開的文件是輸入文件,若文件不存在則返回

                              //打開失敗信息。

    ios::in | ios::out        //規定打開的文件同時用於輸入和輸出。

ios::app | ios::nocreate //規定只向打開的文件尾追加數據,若文件不存在

                          //則返回打開失敗信息。

    ios::out | ios::noreplace //規定打開的文件是輸出文件,若文件存在則返回

                               //打開失敗信息。

ios::in | ios::out | ios::binary //規定打開的文件是二進制文件,並可同時

                                      //用於輸入和輸出。

    (2) 使用open成員函數打開一個文件時,若由字符指針參數所指定的文件不存在,則就建立該文件,當然建立的新文件是一個長度爲0的空文件,但若打開方式參數中含有ios::nocreate選項,則不建立新文件,並且返回打開失敗信息。

    (3) 當打開方式中不含有ios::ate或ios::app選項時,則文件指針被自動移到文件的開始位置,即字節地址爲0的位置。當打開方式中含有 ios::out選項,但不含有ios::in,ios::ate或ios::app選項時,若打開的文件存在,則原有內容被清除,使之變爲一個空文件。

    (4) 當用輸入文件流對象調用open成員函數打開一個文件時,打開方式參數可以省略,缺省按ios::in方式打開,若打開方式參數中不含有ios::in選 項時,則會自動被加上。當用輸出文件流對象調用open成員函數打開一個文件時,打開方式參數也可以省略,缺省按ios::out方式打開,若打開方式參 數中不含有ios::out選項時,則也會自動被加上。

    下面給出定義文件流對象和打開文件的一些例子:

    (1) ofstream fout;

        fout.open(a://xxk.dat); //字符串中的雙反斜線表示一個反斜線

(2) ifstream fin;

    fin.open(a://wr.dat, ios::in | ios::nocreate);

    (3) ofstream ofs;

        ofs.open(a://xxk.dat, ios::app);

(4) fstream fio;

    fio.open(a://abc.ran, ios::in | ios::out | ios::binary);

    例 子(1)首先定義了一個輸出文件流對象fout,使系統爲其分配一個文件緩衝區,然後調用open成員函數打開a盤上的xxk.dat文件,由於調用的成 員函數省略了打開方式參數,所以採用缺省的ios::out方式。執行這個調用時,若a:xxk.dat文件存在,則清除該文件內容,使之成爲一個空文 件,若該文件不存在,則就在a盤上建立名爲xxk.dat的空文件。通過fout流打開a:xxk.dat文件後,以後對fout流的輸出操作就是對 a:xxk.dat文件的輸出操作。

    例子(2)首先定義了一個輸入文件流對象fin,並使其在內存中得到一個文件緩衝區,然後打開a盤上的wr.dat文件,並規定以輸入方式進行訪問,若該文件不存在則不建立新文件,使打開該文件的操作失敗,此時由fin帶回0值,由(!fin)是否爲真判斷打開是否失敗。

    例子(3)首先定義了一個輸出文件流對象ofs,同樣在內存中得到一個文件緩衝區,然後打開a盤上已存在的xxk.dat文件,並規定以追加數據的方式訪問,即不破壞原有文件中的內容,只允許向尾部寫入新的數據。

    例子(4)首先定義了一個輸入輸出文件流對象fio,同樣在內存中得到一個文件緩衝區,然後按輸入和輸出方式打開a盤上的abc.ran二進制文件。此後既可以按字節向該文件寫入信息,又可以從該文件讀出信息。

    在 每一種文件流類中,既定義有無參構造函數,又定義有帶參構造函數,並且所帶參數與open成員函數所帶參數完全相同。當定義一個帶有實參表的文件流對象 時,將自動調用相應的帶參構造函數,打開第一個實參所指向的文件,並規定按第二個實參所給的打開方式進行操作。所以它同先定義不帶參數的文件流對象,後通 過流對象調用open成員函數打開文件的功能完全相同。對於上述給出的四個例子,依次與下面的文件流定義語句功能相同。

    (1) ofstream fout(a://xxk.dat);

    (2) ifstream fin(a://wr.dat, ios::in | ios::nocreate);

    (3) ofstream ofs(a://xxk.dat, ios::app);

    (4) fstream ofs(a:/abc.ran, ios::in | ios::out | ios::binary);

    每 個文件流類中都提供有一個關閉文件的成員函數close(),當打開的文件操作結束後,就需要關閉它,使文件流與對應的物理文件斷開聯繫,並能夠保證最後 輸出到文件緩衝區中的內容,無論是否已滿,都將立即寫入到對應的物理文件中。文件流對應的文件被關閉後,還可以利用該文件流調用open成員函數打開其他 的文件。

   關閉任何一個流對象所對應的文件,就是用這個流對象調用close()成員函數即可。如要關閉fout流所對應的a:/xxk.dat文件,則關閉語句爲:

        fout.close();

發佈了38 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章