首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C/C++ 讀取包含空字符的「行」:突破 getline 的 \0 限制

     編輯:程式設計綜合問答

為什麼 std::getline 讀不完二進制文件?怎麼真正按「行」讀取含 \0 的數據

標準庫 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++ std::string 支持內嵌 \0

自 C++11 起,std::string 由長度而非 \0 決定內容,可安全存儲二進制數據:

std::string s("abc\0def", 7);  // 長度 7,包含 \0
std::cout << s.size();         // 輸出 7

C 語言方案:fread + 手動掃描

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 的場景。
  • 二進制或混合文件:一次性讀入內存,手動按 \n 分割,保留所有 \0。
  • C++ 用 std::string/vector<char> 存二進制安全;C 用 fread + 長度參數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved