標準庫 std::getline 以 '\n' 為分隔符,但 C/C++ 字符串以 '\0' 結束。若文件中夾雜 \0(如 .c 文件含字符串字面量),getline 讀取的字符串會在第一個 \0 截斷,導致後續內容丟失。
// 文件 content.bin: "line1\0middle\nline2\n"
std::ifstream f("content.bin");
std::string line;
std::getline(f, line); // line == "line1",實際讀取位置停在 \0 後
// 後續 getline 會繼續從 \0 後讀,但 string 已截斷
不依賴 C 風格字符串,直接操作 std::vector<char> 或 std::string 的二進制模式:
std::vector<char> readLinesWithNulls(const std::string& filepath) {
std::ifstream f(filepath, std::ios::binary | std::ios::ate);
if (!f) throw std::runtime_error("Open failed");
std::streamsize size = f.tellg();
f.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (!f.read(buffer.data(), size)) throw std::runtime_error("Read failed");
return buffer; // 包含所有 \0 和 \n 的原始數據
}
// 手動分割「行」(以 \n 為界,保留 \0)
std::vector<std::string> splitLines(const std::vector<char>& data) {
std::vector<std::string> lines;
std::string current;
current.reserve(256);
for (char c : data) {
if (c == '\n') {
lines.emplace_back(std::move(current));
current.clear();
} else {
current.push_back(c); // \0 也會被存入 string(C++11 允許 string 含 \0)
}
}
if (!current.empty()) lines.emplace_back(std::move(current));
return lines;
}
自 C++11 起,std::string 由長度而非 \0 決定內容,可安全存儲二進制數據:
std::string s("abc\0def", 7); // 長度 7,包含 \0
std::cout << s.size(); // 輸出 7
FILE* fp = fopen("data.bin", "rb");
fseek(fp, 0, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* buf = malloc(sz + 1);
fread(buf, 1, sz, fp);
buf[sz] = '\0'; // 便於字符串函數處理,但實際長度用 sz
// 掃描 \n 分割,指針記錄每行起止位置
char* line_start = buf;
for (char* p = buf; p < buf + sz; ++p) {
if (*p == '\n') {
// 處理 [line_start, p) 區間,長度 p - line_start
process_line(line_start, p - line_start);
line_start = p + 1;
}
}
free(buf);
getline 適合純文本、無內嵌 \0 的場景。std::string/vector<char> 存二進制安全;C 用 fread + 長度參數。