C++文件流式編程的優(yōu)勢詳解
C++文件流式編程優(yōu)勢
文件操作是很多程序都會用到的功能,在c語言中,常常使用FILE*指針和一系列標準庫函數(如fopen、fclose、fread、fwrite、fprintf、fscanf)進行文件操作,看看一段c語言的文件操作代碼
#include <stdio.h>
FILE* fp = fopen("data.txt", "r");
if (fp == NULL) { perror("打開失敗"); return -1; }
int num;
while (fscanf(fp, "%d", &num) != EOF) { // 需手動檢查返回值
printf("讀取到: %d\n", num);
}
fclose(fp); // 必須手動關閉,否則泄漏資源c語言作為一個面向過程的語言,上面的操作就充分體現了這個特點,通過函數打開——讀取/寫入——關閉的一系列過程,完成對文件的操作。
而且格式化寫入的過程中,要靠人工保證匹配正確性, 一旦格式不匹配時就會導致運行時錯誤
下面來看看C++是怎么做的
#include <iostream>
#include <fstream> // C++文件流頭文件
int main() {
std::ofstream outFile("example.txt"); // 創(chuàng)建輸出文件流(寫入模式)
if (!outFile) { // 檢查文件是否成功打開
std::cerr << "文件打開失敗!" << std::endl;
return 1;
}
outFile << "Hello, C++!" << std::endl; // 使用 << 操作符寫入數據
outFile.close(); // 關閉文件(析構時也會自動關閉)
return 0;
}是不是很眼熟?
寫文件跟打印輸出的寫法很類似,把要寫的內容輸出到文件對象就可以了,非常直觀,也不用考慮格式匹配的問題。
這就是c++的面對對象的實現方式帶來的優(yōu)勢
從函數調用到對象交互
C++文件操作的革命性變化在于將文件操作封裝為流對象,通過<<(插入)和>>(提取)運算符實現類型安全的讀寫。
文件操作最常用的三個類是:
ifstream:文件輸入對象(讀操作)ofstream:文件輸出對象(寫操作)fstream:文件輸入輸出對象(讀寫操作)
對文件操作時,就根據具體的操作創(chuàng)建不同的類對象,創(chuàng)建對象時指定文件就相當于打開了文件,然后對文件對象進行流操作就可以了,看看具體的例子:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// 寫入文件
ofstream outFile("test_cpp.txt"); //創(chuàng)建即打開文件
if (!outFile.is_open()) { //判斷是否正常打開
cerr << "無法打開文件進行寫入" << endl;
return 1;
}
outFile << "Hello, C++ File!" << endl;
outFile << "這是第二行內容" << endl;
outFile.close(); // 可以省略,析構函數會自動關閉
// 讀取文件
ifstream inFile("test_cpp.txt");
if (!inFile) { // 等價于!inFile.is_open()
cerr << "無法打開文件進行讀取" << endl;
return 1;
}
string line;
cout << "文件內容:" << endl;
while (getline(inFile, line)) { // 逐行讀取
cout << line << endl;
}
// 檢查是否正常讀取結束
if (inFile.eof()) {
cout << "讀取完成" << endl;
} else if (inFile.fail()) {
cerr << "讀取過程中發(fā)生錯誤" << endl;
}
return 0;
}了使用流操作符>>,<<外,也可以使用read,write方法對文件進行讀寫,特別是對二進制文件的讀寫
#include <iostream>
#include <fstream>
int main()
{
int num = 42;
double pi = 3.14159;
// 寫入二進制文件
std::ofstream binOut("data.bin", std::ios::binary);
binOut.write(reinterpret_cast<const char*>(&num), sizeof(num)); //寫入num
binOut.write(reinterpret_cast<const char*>(&pi), sizeof(pi)); //寫入pi
binOut.close();
// 讀取二進制文件
std::ifstream binIn("data.bin", std::ios::binary);
int readNum;
double readPi;
//讀取一個int數據到readnum
binIn.read(reinterpret_cast<char*>(&readNum), sizeof(readNum));
//讀取一個double數據到readPi
binIn.read(reinterpret_cast<char*>(&readPi), sizeof(readPi));
binIn.close();
std::cout << "讀取的數字: " << readNum << ", Pi: " << readPi << std::endl;
return 0;
}RAII機制保障資源安全釋放
RAII機制(資源獲取即初始化)是C++流安全的基石:流對象在析構時自動調用close(),無論函數正常返回還是異常退出,都能確保資源釋放。
對比C語言中需要在每個return前調用fclose的繁瑣,C++實現了"一次聲明,全程無憂"的資源管理。
如下面代碼:
#include <fstream>
using namespace std;
int main()
{
ifstream in("data.txt"); // 構造即打開文件,RAII自動管理
int num;
// 流對象在布爾上下文自動轉換為!fail(),簡潔判斷讀取狀態(tài)
while (in >> num) { // 類型安全:若num類型不匹配,編譯報錯
cout << "讀取到: " << num << endl;
}
// 無需手動close,in析構時自動釋放資源
return 0;
}當然,也可以使用close方法手動關閉文件流
錯誤處理:流狀態(tài)標志
C++流對象內置狀態(tài)標志,可通過good()/fail()/eof()精準判斷錯誤類型:
ifstream in("data.txt");
if (!in) {
if (in.eof()) cerr << "已到文件尾";
else if (in.fail()) cerr << "格式錯誤";
else if (in.bad()) cerr << "致命錯誤";
}對比C語言需要組合feof/ferror的繁瑣判斷,C++流狀態(tài)管理更清晰高效。
二進制文件隨機存取
c++文件流對象也支持對文件隨機存取,而且定義了輸入和輸出兩個文件指針,分別用seekg和seekp方法來獲取。
另外還有提供了指示文件位置的幾個常量
- ios_base::beg 文件開始處,相當于SEEK_SET
- ios_bae::cur 當前文件指針位置,相當于SEEK_CUR
- ios_base::end 文件結尾處,相當于SEEK_END
具體例子
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Student {
int id;
char name[20];
float score;
};
int main()
{
// 二進制寫入
ofstream outFile("students.dat", ios::binary);
if (!outFile) {
cerr << "無法打開文件進行寫入" << endl;
return 1;
}
Student s1 = {1, "張三", 90.5};
Student s2 = {2, "李四", 85.0};
outFile.write(reinterpret_cast<const char*>(&s1), sizeof(s1));
outFile.write(reinterpret_cast<const char*>(&s2), sizeof(s2));
outFile.close();
// 二進制讀取和隨機訪問
ifstream inFile("students.dat", ios::binary);
if (!inFile) {
cerr << "無法打開文件進行讀取" << endl;
return 1;
}
// 移動到第二個學生的位置
inFile.seekg(sizeof(Student), ios::beg);
Student s;
inFile.read(reinterpret_cast<char*>(&s), sizeof(s));
cout << "學號: " << s.id << endl;
cout << "姓名: " << s.name << endl;
cout << "成績: " << s.score << endl;
// 獲取文件大小
inFile.seekg(0, ios::end); //移動到文件結尾
streampos fileSize = inFile.tellg(); //獲取文件指針當前位置
cout << "文件大小: " << fileSize << " 字節(jié)" << endl;
cout << "學生數量: " << fileSize / sizeof(Student) << endl;
return 0;
}順便提一下,隨機訪問一般只對二進制文件使用,因為文本文件可能由于文件編碼和換行符的影響導致文件指針偏移量計算出現誤差,從而出錯
最后做個c和c++文件操作的簡單對比
對比項 | C語言(stdio.h) | C++(<fstream>流) |
|---|---|---|
文件操作方式 | FILE*+ 函數(fopen、fprintf) | 流類(ofstream、ifstream) |
語法 | 函數式(fprintf) | 流式(<<和 >>) |
錯誤處理 | 返回值(如NULL) | fail()、eof()、bad() |
資源管理 | 手動fclose | RAII(自動關閉) |
二進制支持 | fread/fwrite | write/read(需std::ios::binary) |
易用性 | 較低(函數多) | 更高(流操作直觀) |
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
C++20新增屬性[[no_unique_address]]詳解(最新整理)
[[no_unique_address]]讓空類型的類數據成員有機會不再占用額外的內存空間,從而減輕了因為地址規(guī)定帶來的性能影響,同時還讓空基類優(yōu)化代碼得到了簡化的機會,本文給大家詳細介紹C++20新增屬性[[no_unique_address]],感興趣的朋友一起看看吧2025-09-09
OPENMP?SECTIONS?CONSTRUCT原理示例解析
這篇文章主要為大家介紹了OPENMP?SECTIONS?CONSTRUCT原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
c++ vector(向量)使用方法詳解(順序訪問vector的多種方式)
vector是向量類型,它可以容納許多類型的數據,如若干個整數,所以稱其為容器,本文介紹一下使用方法2013-12-12
C++ 中使用lambda代替 unique_ptr 的Deleter的方法
這篇文章主要介紹了C++ 中使用lambda代替 unique_ptr 的Deleter的方法,需要的朋友可以參考下2017-04-04

