C++ —— 文件操作(流式操作)
- ofstream
- 文件創建
- 文件寫入
- ofstream 文件打開模式
- std::ios::out 寫入模式
- std::ios::app 追加模式
- std::ios::trunc 截斷
- std::ios::binary 二進制
- std::ios::ate at the end模式
- ifstream
- std::ios::in 讀取模式(默認)
- std::ios::binary
- 模式組合
- 常見組合
- 特殊模式說明
- std::ios::ate (At End)
- 重要注意事項
- 完整示例
- 模式總結表
- fstream
- C++ `fstream` 文件流詳解
- 基本用法
- 1. 頭文件
- 2. 打開文件
- 3. 檢查文件是否成功打開
- 文件打開模式
- 讀寫操作
- 寫入文件
- 讀取文件
- 二進制讀寫
- 文件指針控制
- 獲取當前位置
- 移動指針
- 完整示例
- 注意事項
- 文件流的成員函數
- **1. 打開/關閉文件**
- **2. 狀態檢查**
- **3. 讀寫操作**
- **基本讀寫**
- **二進制讀寫**
- **4. 文件指針操作**
- **5. 其他功能**
- **示例代碼**
- **注意事項**
- 流式文件操作和一般的文件操作函數區別
- **1. 設計理念**
- **2. 使用方式對比**
- **(1)打開文件**
- **(2)讀寫數據**
- **(3)關閉文件**
- **3. 核心區別**
- **4. 適用場景**
- **優先使用流式操作的情況**
- **優先使用一般函數的情況**
- **5. 代碼示例對比**
- **示例 1:復制文本文件**
- **示例 2:讀取二進制數據**
- **總結**
我們之前已經了解過了C語言的文件操作,如果大家對著一塊不是很了解的話,可以點擊這里:
https://blog.csdn.net/qq_67693066/article/details/135588933?spm=1011.2415.3001.5331
我們來看看C++對于文件操作是怎么辦的:
ofstream
ofstream(Output File Stream)是 C++ 中用于寫入文件的類,屬于 fstream 庫。
文件創建
int main()
{std::ofstream file("myfile.txt");//檢查是否創建成功// 檢查是否創建成功if (!file) {std::cout << "文件創建失敗!";return 1;}std::cout << "文件創建成功!";return 0;
}
運行成功的話,可以在項目的路徑下看見新創建的文件:
文件寫入
ofstream的寫入直接用 << 就可以了:
int main()
{std::ofstream file("myfile.txt");if (file) {file << "姓名: 張三\n"; // 寫入字符串file << "年齡: " << 25 << "\n"; // 混合寫入file << "身高: " << 175.5 << "cm\n";}return 0;
}
ofstream 文件打開模式
ofstream 提供了多種文件打開模式,通過位掩碼(std::ios 中的枚舉)組合使用:
std::ios::out 寫入模式
std::ios::out,文件存在時會清空文件內容,文件不存在的話會創建新的文件,我們可以來試驗一下,我剛剛在前面的介紹中往文件中寫入了一些文字:
我們重新執行一次代碼:
int main()
{std::ofstream file("myfile.txt",std::ios::out); //默認模式return 0;
}
std::ios::app 追加模式
std::ios::app允許你在創建完文件之后,之后再次往文件當中追加內容:
int main()
{//std::ofstream file("myfile.txt",std::ios::out); //默認模式std::ofstream file("myfile.txt", std::ios::app);if (file){file << "I am wiriting\n";}return 0;
}
std::ios::trunc 截斷
如果文件已存在,清空文件內容(與 ios::out 默認行為相同)
int main()
{//std::ofstream file("myfile.txt",std::ios::out); //默認模式//std::ofstream file("myfile.txt", std::ios::app);std::ofstream file("myfile.txt", std::ios::trunc);return 0;
}
std::ios::binary 二進制
std::ios::binary 是 C++ 文件流的一個打開模式,用于以二進制形式讀寫文件,避免文本模式下的字符轉換:
適用場景:
- 讀寫非文本文件(如圖片、音頻、視頻、壓縮包等)。
- 精確控制文件內容,避免文本模式下的自動轉換。
int main()
{// 以二進制模式寫入文件(如果文件存在,會被覆蓋)std::ofstream file("data.bin", std::ios::binary | std::ios::out);if (!file) {std::cerr << "Failed to open file!" << std::endl;return 1;}int num = 12345;double pi = 3.14159;char str[] = "Hello Binary!";// 直接寫入二進制數據file.write(reinterpret_cast<const char*>(&num), sizeof(num));file.write(reinterpret_cast<const char*>(&pi), sizeof(pi));file.write(str, sizeof(str)); // 包括 '\0' 結束符file.close();std::cout << "Binary data written to data.bin" << std::endl;}
std::ios::ate at the end模式
std::ios::ate 創建之后文件指針的位置就會放在最后,并且可以通過seekp來移動文件指針位置,重新輸入內容:
int main()
{std::ofstream file("myfile.txt", std::ios::ate);file << "I am writing " << endl;file.seekp(3);file << "This is a another setence " << endl;return 0;
}
ifstream
std::ifstream 是 C++ 標準庫中專門用于從文件讀取數據的輸入流類,繼承自 std::istream。它是文件操作三大類之一(另外兩個是 ofstream 和 fstream)。
std::ios::in 讀取模式(默認)
std::ios::in 以讀取模式打開,文件必須存在,否則會失敗:
#include<fstream>int main()
{std::ofstream file1("myfile.txt", std::ios::ate);file1 << "I am writing " << endl;file1.seekp(3);file1 << "This is a another setence " << endl;std::ifstream file2("myfile.txt", std::ios::in);//獲取文件大小file2.seekg(0, std::ios::end);std::streampos fileSize = file2.tellg();file2.seekg(0);std::cout << "文件大小: " << fileSize << " 字節" << std::endl;char* buffer = new char[1024*1024]; file2.read(buffer, fileSize);buffer[fileSize] = '\0'; // 添加終止符printf("%s\n", buffer);return 0;
}
std::ios::binary
- 作用:以二進制模式打開文件
- 特點:
- 避免文本模式下的字符轉換(如換行符轉換)
- 適合讀取非文本文件(如圖片、視頻等)
- 示例:
std::ifstream binFile("image.jpg", std::ios::binary);
模式組合
可以組合多個模式使用,使用按位或運算符 |
:
常見組合
-
普通文本讀取:
std::ifstream textFile("text.txt", std::ios::in);
-
二進制讀取:
std::ifstream binFile("data.bin", std::ios::in | std::ios::binary);
-
從文件末尾開始讀取:
std::ifstream file("log.txt", std::ios::in | std::ios::ate);
特殊模式說明
std::ios::ate (At End)
- 作用:打開文件后立即定位到文件末尾
- 特點:
- 可以先用
tellg()
獲取文件大小 - 之后可以用
seekg()
移動到任意位置讀取
- 可以先用
- 示例:
std::ifstream file("data.txt", std::ios::in | std::ios::ate); if (file.is_open()) {std::streampos size = file.tellg(); // 獲取文件大小file.seekg(0); // 回到文件開頭開始讀取// ...讀取操作... }
重要注意事項
-
文件不存在:
- 如果文件不存在且只使用
std::ios::in
,打開會失敗 - 檢查是否成功打開:
if (!file.is_open()) {// 處理錯誤 }
- 如果文件不存在且只使用
-
模式兼容性:
ifstream
不支持寫入模式(如std::ios::out
)- 如果需要寫入,應使用
fstream
-
二進制模式:
- 在Windows平臺上,文本模式會自動轉換
\r\n
為\n
- 二進制模式保持原始字節不變
- 在Windows平臺上,文本模式會自動轉換
-
默認行為:
- 如果不指定任何模式,默認是
std::ios::in
- 如果不指定二進制模式,默認是文本模式
- 如果不指定任何模式,默認是
完整示例
#include <fstream>
#include <iostream>int main() {// 以二進制模式打開文件并從末尾開始std::ifstream file("data.dat", std::ios::in | std::ios::binary | std::ios::ate);if (!file.is_open()) {std::cerr << "無法打開文件" << std::endl;return 1;}// 獲取文件大小std::streampos fileSize = file.tellg();std::cout << "文件大小: " << fileSize << " 字節" << std::endl;// 回到文件開頭file.seekg(0, std::ios::beg);// 讀取文件內容char* buffer = new char[fileSize];file.read(buffer, fileSize);// 處理數據...delete[] buffer;file.close();return 0;
}
模式總結表
模式標志 | 描述 | 適用場景 |
---|---|---|
std::ios::in | 讀取模式(默認) | 普通文本文件讀取 |
std::ios::binary | 二進制模式 | 非文本文件讀取 |
std::ios::ate | 打開后定位到文件末尾 | 需要先獲取文件大小的場景 |
fstream
fstream其實是ofstream和ifstream的結合:
C++ fstream
文件流詳解
fstream
是 C++ 標準庫中用于文件輸入輸出的流類,它結合了 ifstream
(輸入)和 ofstream
(輸出)的功能,允許對文件進行讀寫操作。
基本用法
1. 頭文件
#include <fstream>
2. 打開文件
std::fstream file;
file.open("example.txt", std::ios::in | std::ios::out);
或者直接初始化:
std::fstream file("example.txt", std::ios::in | std::ios::out);
3. 檢查文件是否成功打開
if (!file.is_open()) {std::cerr << "無法打開文件" << std::endl;return 1;
}
文件打開模式
fstream
支持多種打開模式,可以用位或運算符 |
組合:
模式標志 | 描述 |
---|---|
std::ios::in | 讀取模式(文件必須存在) |
std::ios::out | 寫入模式(創建或覆蓋文件) |
std::ios::app | 追加模式(所有寫入在文件末尾) |
std::ios::ate | 打開后定位到文件末尾 |
std::ios::binary | 二進制模式(避免字符轉換) |
std::ios::trunc | 如果文件存在,先清空內容 |
讀寫操作
寫入文件
file << "寫入一行文本\n";
file << "數字: " << 42 << std::endl;
讀取文件
std::string line;
while (std::getline(file, line)) {std::cout << line << std::endl;
}
二進制讀寫
// 寫入二進制數據
int data = 12345;
file.write(reinterpret_cast<char*>(&data), sizeof(data));// 讀取二進制數據
int readData;
file.read(reinterpret_cast<char*>(&readData), sizeof(readData));
文件指針控制
獲取當前位置
std::streampos pos = file.tellg(); // 獲取讀取位置
pos = file.tellp(); // 獲取寫入位置
移動指針
file.seekg(0, std::ios::beg); // 將讀取指針移動到文件開頭
file.seekp(10, std::ios::cur); // 將寫入指針從當前位置移動10字節
完整示例
#include <fstream>
#include <iostream>
#include <string>int main() {// 打開文件用于讀寫(不存在則創建)std::fstream file("data.txt", std::ios::in | std::ios::out | std::ios::trunc);if (!file.is_open()) {std::cerr << "無法打開文件" << std::endl;return 1;}// 寫入數據file << "第一行\n";file << "第二行\n";file << 123 << " " << 3.14 << std::endl;// 回到文件開頭讀取file.seekg(0);std::string line;while (std::getline(file, line)) {std::cout << "讀取到: " << line << std::endl;}file.close();return 0;
}
注意事項
- 模式組合:
fstream
沒有默認模式,必須顯式指定in
或out
- 文件存在性:使用
in
模式時文件必須存在 - 二進制模式:處理非文本文件時應使用
binary
模式 - 指針同步:讀寫切換時需要調用
seekg()
或seekp()
- 內存管理:使用
write()
寫入二進制數據時要注意數據對齊
fstream
提供了靈活的文件操作能力,適合需要同時讀寫文件的場景。對于簡單的只讀或只寫操作,可以考慮使用 ifstream
或 ofstream
。
文件流的成員函數
在 C++ 中,文件流相關的類(如 ifstream
, ofstream
, fstream
)提供了許多成員函數來操作文件。以下是常見的文件流成員函數分類說明:
1. 打開/關閉文件
-
open()
打開文件,與流關聯。void open(const char* filename, ios_base::openmode mode = ios_base::in | ios_base::out);
filename
:文件路徑mode
:打開模式(如ios::in
,ios::out
,ios::binary
,ios::app
等)。
-
close()
關閉文件,釋放資源。void close();
2. 狀態檢查
-
is_open()
檢查文件是否成功打開。bool is_open() const;
-
good()
/eof()
/fail()
/bad()
檢查流狀態:good()
:操作是否正常(無錯誤)。eof()
:是否到達文件末尾(End-of-File)。fail()
:操作是否失敗(可恢復錯誤,如類型不匹配)。bad()
:是否發生嚴重錯誤(如文件損壞)。
3. 讀寫操作
基本讀寫
-
>>
(提取運算符)
從文件讀取數據(格式化輸入)。ifstream file("input.txt"); int value; file >> value; // 讀取一個整數
-
<<
(插入運算符)
向文件寫入數據(格式化輸出)。ofstream file("output.txt"); file << "Hello, World!" << endl;
二進制讀寫
-
read()
從文件讀取二進制數據。istream& read(char* buffer, streamsize size);
buffer
:存儲數據的緩沖區。size
:要讀取的字節數。
-
write()
向文件寫入二進制數據。ostream& write(const char* buffer, streamsize size);
4. 文件指針操作
-
tellg()
/tellp()
獲取當前讀寫位置:tellg()
:返回輸入流(讀)的指針位置(ifstream
)。tellp()
:返回輸出流(寫)的指針位置(ofstream
)。
-
seekg()
/seekp()
移動文件指針:istream& seekg(streampos pos); // 移動到絕對位置 istream& seekg(streamoff offset, ios_base::seekdir dir); // 相對位置移動
pos
:絕對位置。offset
:偏移量。dir
:基準位置(ios::beg
開頭,ios::cur
當前位置,ios::end
結尾)。
5. 其他功能
-
flush()
強制刷新輸出緩沖區(立即寫入文件)。ostream& flush();
-
peek()
查看下一個字符但不移動指針。int peek();
-
get()
/getline()
讀取字符或一行:int get(); // 讀取單個字符 istream& getline(char* buffer, streamsize size); // 讀取一行
示例代碼
#include <fstream>
#include <iostream>
using namespace std;int main() {// 寫入文件ofstream out("test.txt");if (out.is_open()) {out << "Line 1\nLine 2" << endl;out.close();}// 讀取文件ifstream in("test.txt");if (in.is_open()) {string line;while (getline(in, line)) {cout << line << endl;}in.close();}return 0;
}
注意事項
- 模式標志:
ios::in
(讀)、ios::out
(寫)、ios::binary
(二進制)、ios::app
(追加)等可組合使用。
- 錯誤處理:
始終檢查is_open()
或good()
避免未定義行為。 - 資源釋放:
顯式調用close()
或依賴析構函數自動關閉。
根據需求選擇合適的函數組合即可高效操作文件!
流式文件操作和一般的文件操作函數區別
在 C++ 中,流式文件操作(基于 fstream
/ifstream
/ofstream
)和 一般文件操作函數(基于 C 語言的 FILE*
或系統 API)是兩種不同的文件處理方式,它們在設計理念、使用方式和適用場景上有顯著區別。以下是詳細對比:
1. 設計理念
特性 | 流式文件操作 (fstream 等) | 一般文件操作函數 (fopen /read /Write 等) |
---|---|---|
封裝層次 | 高級封裝,面向對象(基于 std::iostream 類體系) | 低級封裝,面向過程(函數調用) |
數據視角 | 將文件視為連續的字符流或對象序列 | 將文件視為字節塊或二進制數據 |
緩沖區管理 | 自動緩沖(默認),支持手動刷新 (flush ) | 需手動管理緩沖區(如 setvbuf ) |
錯誤處理 | 通過流狀態標志(good() , fail() )或異常機制 | 通過返回值(如 NULL 或 -1 )和全局 errno |
2. 使用方式對比
(1)打開文件
- 流式操作:
#include <fstream> std::ifstream fin("input.txt", std::ios::binary); // 二進制模式 std::ofstream fout("output.txt");
- 一般函數:
#include <cstdio> FILE* fin = fopen("input.txt", "rb"); // C 風格 int fd = open("input.txt", O_RDONLY); // POSIX API
(2)讀寫數據
- 流式操作(類型安全):
int num; fin >> num; // 格式化讀取(文本) fout << "Hello" << std::endl; // 格式化寫入fin.read(buffer, size); // 二進制讀取 fout.write(buffer, size); // 二進制寫入
- 一般函數(直接操作字節):
fscanf(fin, "%d", &num); // C 格式化讀取 fprintf(fout, "Hello\n");fread(buffer, 1, size, fin); // C 二進制讀取 write(fd, buffer, size); // POSIX 寫入
(3)關閉文件
- 流式操作(自動析構):
fin.close(); // 可省略,析構時自動調用
- 一般函數(需顯式關閉):
fclose(fin); // C 風格 close(fd); // POSIX
3. 核心區別
對比項 | 流式文件操作 | 一般文件操作函數 |
---|---|---|
類型安全 | ? 支持運算符重載(<< />> ),避免類型錯誤 | ? 需手動匹配格式字符串(如 %d vs %f ) |
性能 | ?? 默認有緩沖,適合高頻小數據量操作 | ?? 無緩沖時更快,適合大塊二進制數據 |
靈活性 | ? 高級封裝,底層控制受限(如精確指針移動) | ? 直接操作文件描述符/指針,控制更精細 |
跨平臺性 | ? 標準 C++ 實現,跨平臺一致 | ?? C 庫跨平臺,但系統 API(如 open )需適配 |
異常支持 | ? 可通過 exceptions() 啟用異常 | ? 僅通過返回值/errno 處理錯誤 |
4. 適用場景
優先使用流式操作的情況
- 需要 類型安全 的文本讀寫(如配置文件、日志)。
- 代碼已基于 C++ 標準庫,希望保持風格統一。
- 簡單的逐行或格式化數據處理(如
getline
讀取 CSV)。
優先使用一般函數的情況
- 需要 高性能二進制操作(如大文件拷貝、網絡數據傳輸)。
- 依賴 系統特定功能(如文件鎖、內存映射)。
- 遺留項目或與 C 語言交互的代碼。
5. 代碼示例對比
示例 1:復制文本文件
- 流式操作:
std::ifstream src("source.txt"); std::ofstream dst("dest.txt"); dst << src.rdbuf(); // 一行完成拷貝
- 一般函數:
FILE* src = fopen("source.txt", "r"); FILE* dst = fopen("dest.txt", "w"); char buffer[4096]; while (size_t len = fread(buffer, 1, sizeof(buffer), src)) {fwrite(buffer, 1, len, dst); } fclose(src); fclose(dst);
示例 2:讀取二進制數據
- 流式操作:
std::ifstream file("data.bin", std::ios::binary); int value; file.read(reinterpret_cast<char*>(&value), sizeof(value));
- 一般函數:
FILE* file = fopen("data.bin", "rb"); int value; fread(&value, sizeof(value), 1, file);
總結
- 流式操作:適合 高層抽象、類型安全 的場景,代碼簡潔但靈活性較低。
- 一般函數:適合 底層控制、高性能二進制處理,但需手動管理資源。
根據項目需求選擇合適的方式,現代 C++ 項目推薦優先使用 <fstream>
,除非有明確的性能或控制需求。