文件 I/O 是 C++ 開發的基礎技能。本文對比 C 標準庫(stdio.h)與 C++ 標準庫(fstream)兩種讀取文件的主流方式,分析優缺點與適用場景,提供生產級代碼範例。
FILE*)適合需精確控制緩衝區、二進制讀寫、或與 C 代碼互操作的場景。
- // 讀取整個文件到記憶體
- char* readFileC(const char* path, long& outLen) {
- FILE* fp = fopen(path, "rb"); // 二進制模式避免換行轉換
- if (!fp) return nullptr;
- fseek(fp, 0, SEEK_END);
- long len = ftell(fp);
- rewind(fp);
- char* buf = new char[len + 1];
- if (buf) {
- size_t read = fread(buf, 1, len, fp);
- buf[read] = '\0'; // 確保字串結尾
- }
- fclose(fp);
- outLen = len;
- return buf; // 呼叫端負責 delete[]
- }
fseek/ftell 獲取大小需注意 32 位系統 long 可能不足 2GB,大文件應用 fseeko/ftello 或 _fseeki64。"rb" 避免 Windows 下 \r\n 轉換導致位置計算偏差。ifstream)類型安全、支援字串直接讀取、異常處理、區域化設定,是現代 C++ 首選。
- #include <fstream> // ifstream
- #include <string>
- #include <vector>
- // 逐行讀取文本文件
- bool readLines(const std::string& path, std::vector<std::string>& lines) {
- std::ifstream in(path);
- if (!in) return false;
- std::string line;
- while (std::getline(in, line)) {
- lines.push_back(line);
- }
- return true;
- }
- // 一次性讀取整個文件到字串(C++11)
- std::string readAll(const std::string& path) {
- std::ifstream in(path, std::ios::binary | std::ios::ate);
- if (!in) throw std::runtime_error("Cannot open file");
- std::streamsize size = in.tellg();
- in.seekg(0, std::ios::beg);
- std::string buffer(size, '\0');
- if (!in.read(&buffer[0], size)) throw std::runtime_error("Read failed");
- return buffer;
- }
std::getline 自動處理跨平台換行符(\n/\r\n)。exceptions())可強制錯誤拋出,避免忽略失敗。std::stringstream 進行記憶體內格式化解析。| 維度 | C 風格 | C++ 流 |
|---|---|---|
| 執行速度 | 略快(無格式化開銷) | 略慢(區域化、格式化層) |
| 二進制讀寫 | 原生支援 | 需 binary 模式,同等效能 |
| 文字處理 | 手動解析 | 豐富操作符、getline |
| 記憶體安全 | 手動管理,高風險 | RAII,極低風險 |
| 類型安全 | 無 | 強類型 |
| 跨平台換行 | 需自行處理 | 自動處理 |
mmap/ReadFile 等平台 API。
- std::ifstream in("bigfile.dat", std::ios::binary);
- char buffer[65536]; // 64KB 緩衝區
- in.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
可顯著提升大文件讀取吞吐量。
C++ 文件讀取推薦以 fstream 為主,善用 RAII 與標準演算法(如 std::istreambuf_iterator)編寫簡潔健壯的代碼。理解 C 風格底層機制有助於處理特殊場景與效能調優。