概述
計算機中有兩種常見存儲方式:
- 臨時存儲:變量和數組
- 永久存儲:文件
- 保存大量的數據
- 存儲在二級存儲設備中
- Magnetic disks
- Optical disks
- Tapes
文件的基本概念:
C++文件 (file) 分爲兩類:二進制文件和文本文件
文本文件由字符序列組成,也稱ASCII文件。在文本文件中存取的最小信息單位爲字符 (character) 。
二級制文件中存取的最小信息單位爲字節 (Byte) 。
C++把每一個文件都看作一個有序的字節流,每一個文件或者以文件結束符 (EOF) 結束,或者在特定的字節號處結束。
下面我們具體解釋一些重點概念:
Bits (二進制位)
- 0 or 1
- 計算機支持的最小數據項
- 計算機電路執行位處理
- 所有數據項最終由位組成
Characters (字符)
- 數字,字母和專門的符號稱爲字符
- 能夠在特定計算機上用來編寫程序和代表數據項的所有字符的集合稱爲 " 字符集 "
- Char以字節形式存儲 (8 bits)
Fields (字段或數據項)
- 由字符組成
- 代表一定的含義
Records (記錄)
- 由多個字段組成
- 在C++中表現爲:類
- 記錄的關鍵字:A record key is a field unique to each record
C++の流類庫
當打開一個文件時,該文件就和某個流關聯起來了。對文件進行讀寫實際上受到一個文件定位指針 (file position pointer) 的控制。
輸入流指針也稱作讀指針,每一次提取操作將從讀指針當前所指位置開始,每次提取操作自動將讀指針向文章尾移動。
輸出流指針也稱寫指針,每次插入操作將從寫指針當前位置開始,每次插入操作自動將寫指針向文章尾移動。
輸入流:數據從某個載體或設備傳送到內存緩衝區變量
輸出流:數據從內存傳送到某個載體或設備中
程序用 流 統一了對各種計算機設備和文件的操作形式
其中,basic_streambuf不是basic_ios的派生類,而是一個獨立的類,basic_ios有一個保護訪問限制的指針指向它
類basic_streambuf的作用是管理流的緩衝區
iostream預先定義了四個標準流對象:
含義 | 對象 | 備註 | 所屬類 | 默認設備 |
---|---|---|---|---|
標準輸入 | cin | istream類 | 鍵盤 | |
標準輸出 | cout | 緩衝區暫存後標準輸出 | ostream類 | 顯示器 |
標準錯誤輸出 | cerr | 未緩衝 | ostream類 | 顯示器 |
標準錯誤輸出 | clog | 緩衝 | ostream類 | 顯示器 |
文件處理
包含頭文件:#include<fstream>
- 包括三種類模板的定義
basic_ifstream // for file input
basic_ofstream // for file output
basic_fstream // for file input and output
- 提供了處理字符流的模板特化
- ifstream:從文件中讀入字符 (讀文件)
- ofstream:向文件中輸出字符 (寫文件)
- fstream:支持文件中字符的輸入和輸出
- 生成這些流類模板特化的對象,即可打開文件
- 程序和文件之間通過流對象交互
創建文件
輸出流文件
- 創建ofstream文件 (對象)
- 構造函數:
ofstream(const char* filename,int mode)
filename:文件名由文件的主名和擴展名兩部分組成
mode:
ios::out //缺省模式,覆蓋文件中已有數據
ios::app //向文件末尾添加數據
- 構造函數:
ofstream outClientFile("clients.dat",ios::out);
- 對於已創建的文件對象,使用成員函數打開文件
- 與構造函數參數相同:
(const char* filename,int mode)
- 與構造函數參數相同:
ofstream outClientFile;
outClientFile.open("client.dat");
輸入流文件
- 創建ifstream對象
- 構造函數:
ifstream(const char* filename,int mode)
filename:文件名由文件的主名和擴展名兩部分組成
mode:
ios::in //缺省模式,只能從文件讀取數據,最小權限原則
ios::app //向文件末尾添加數據
- 構造函數:
ifstream inClientFile("clients.dat",ios::in);
- 對於已經存在的ifstream對象,使用成員函數打開文件
ifstream inClientFile;
inClientFile.open("clients.dat", ios::in);
文件打開方式 | 含義 |
---|---|
ios::in | 以輸入 (讀) 方式打開文件 |
ios::out | 以輸入 (寫) 方式打開文件 |
ios::app | 打開一個文件使新的內容添加在文件的末尾 |
ios::ate | 打開一個文件使新的內容添加在文件的末尾,但在下次添加時,寫在當前位置處 |
ios::trunc | 若文件存在,則清楚文件所有內容;若文件不存在,則創建新文件 |
ios::binary | 以二進制方式打開文件,缺省時以文本方式打開文件 |
ios::nocreate | 打開一個已有文件,若該文件不存在,則打開失敗 |
ios::noreplace | 若打開的文件已經存在,則打開失敗 |
in:(從文件讀取) 打開方式只要含in
,則在指定的文件不存在的情況下返回失敗。在打開爲輸入輸出方式時(同時使用in
和out
),編程應注意判斷是否失敗,失敗時不可再寫入文件。
out:(寫入文件) 如文件不存在,則建立新文件,如文件存在且未設定app,in
,則文件清空。
trunc:(打開文件,並清空它) 文件不存在時則建立新文件 ,與out默認操作相同。但與in配合時,文件不存在則返回失敗。
app:(寫入文件,添加在末尾) 原文件內容保留,新數據寫在尾部。
ate: (打開文件,文件指針在文件尾) 文件指針可以移動,即新數據可寫到任何位置。文件是否清空由其它標識決定。
注意:
truck/app/ate
最好配合out,in
等一起用。因爲不同的C++平臺 ,要求不同,一起用保證不會出錯。binary
標識以二進制方式打開文件。同時使用out
時,如文件不存在 ,則建立新文件,並且新文件能用,不必清除狀態字。
文件打開方式由在ios類中定義的公有枚舉成員決定:
enum open_mode{
in=0x01,
out=0x02,
ate=0x04,
app=0x08,
trunc=0x10
binary=0x80
};
// Example
fstream iofile; //既輸入又輸出用
iofile.open("myfile.txt",ios::in||ios:out);
三個文件流類都重載了一個帶默認參數的構造函數:
ifstream::ifstream(const char*,int =ios::in,int =filebuf::openprot);
ofstream::ofstream(const char*,int =ios::out,int =filebuf::openprot);
fstream::fstream(const char*,int,int =filebuf::openprot);
文件流類定義了打開文件的成員函數,在文件流對象和磁盤文件名之間建立聯繫:
void ifstream::open(const char*,int =ios::in,int =filebuf::openprot);
void ofstream::open(const char*,int =ios::out,int =filebuf::openprot);
void fstream::open(const char*,int,int =filebuf::openprot);
其中,第三個參數爲指定打開文件的保護方式,一般取默認值
打開文件時應該判斷是否成功
若成功,文件流對象的值 (ta的地址) 非零,不成功爲0 (NULL)
fstream iofile("myfile.txt",ios::in|ios::out);
if (!iofile) { //!爲重載的運算符
cout<<"文件 myfile.txt 打開失敗\n";
return -1;
}
文件的打開與關閉
- 聲明一個文件流對象 (又被稱爲內部文件)
ifstream ifile; // 輸入用
ofstream ofile; // 輸出用
fstream iofile; // 輸入輸出用
- 使用文件流對象的成員函數打開一個磁盤文件
iofile.open("myfile",ios::in||ios::out);
- 使用提取和插入運算符對文件進行讀寫操作,或使用成員函數進行讀寫
- 關閉文件
三個文件流類各有一個關閉文件的成員函數:void ifstream::close();
void ofstream::close();
void fstream::close();
關閉文件時,系統把該文件相關聯的文件緩衝區中的數據寫到文件中,保證文件的完整,收回與該文件相關的內存空間,可供再分配。把磁盤文件名與文件流對象之間的關聯斷開,可防止誤操作修改了磁盤文件。如果要對文件再操作,必須重新打開。
關閉文件並沒有取消文件流對象,該文件流對象又可與其他磁盤文件建立聯繫。文件流對象在程序結束時,或ta的生命期結束時,由析構函數撤消。ta會同時釋放內部分配的預留緩衝區。
實例
向文件中寫數據
#include<iostream>
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::ios;
#include<fstream>
using std::ofstream;
#include<cstdlib>
using std::exit;
int main()
{
ofstream outClientFile("clients.dat",ios::out);
//創建ofstream對象,打開文件
if (!outClientFile) { //重載!,返回true表示文件打開成功
cerr<<"File could not be opened.\n";
exit(1);
}
cout<<"Enter the account, name, and balance.\n"
<<"Enter end-of-file to and input.\n? ";
int account;
char name[30];
double balance;
while (cin>>account>>name>>balance) {
//重載operator void *,當用戶輸入結束符時返回一個空指針
outClientFile<<account<<" "<<name<<" "<<balance<<endl;
//使用<<向文件中寫入數據
cout<<"? ";
}
return 0;
//ofstream的析構函數被隱式調用,關閉文件
}
從文件中讀數據
#include<iostream>
using std::cerr;
using std::cout;
using std::endl;
using std::fixed;
using std::ios;
using std::left;
using std::right;
using std::showpoint;
#include<fstream>
using std::ifstream;
#include<iomanip>
using std::setw;
using std::setprecision;
#include<string>
using std::string;
#include<cstdlib>
using std::exit;
void outputLine(int account,const string name,double balance)
{
cout<<left<<setw(10)<<account<<setw(13)<<name
<<setw(7)<<setprecision(2)<<right<<balance<<endl;
}
int main()
{
ifstream inClientFile("clients.dat",ios::in);
//創建ifstream對象,打開文件
if (!inClientFile) { //重載!,返回true表示文件打開成功
cerr<<"File could not be opened.\n";
exit(1);
}
int account;
char name[30];
double balance;
cout<<left<<setw(10)<<"Account"
<<setw(13)<<"Name"<<"Balance"<<endl<<fixed<<showpoint;
while (inClientFile>>account>>name>>balance)
//重載operator void *,當遇到文件結束符時返回一個空指針
outputLine(account,name,balance);
return 0;
//ifstream的析構函數被隱式調用,關閉文件
}