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

C++ 文件輸出只保留最後一次寫入問題解決

     編輯:程式設計疑難解答

問題現象


void AddEdge(Graph *graph, int v1, int v2) {
    ofstream ocout;
    ocout.open("city.txt");  // 每次呼叫都重新開啟,預設截斷模式
    if (v1 == v2) {
        ocout << "冗余邊" << v1 << " " << v2 << endl;
        return;
    }
    // ... 正常寫入邏輯
}

**結果**:`city.txt` 只有最後一次呼叫的內容,前面全被覆蓋。

根本原因

`ofstream::open()` 預設模式為 `ios::out | ios::trunc`,**每次開啟都會清空文件內容**。

三種解決方案

方案一:追加模式開啟(最簡單)


void AddEdge(int v1, int v2) {
    ofstream ocout("city.txt", ios::app); // ios::app = 追加模式
    if (v1 == v2) {
        ocout << "冗余邊" << v1 << " " << v2 << endl;
        return;
    }
    ocout << v1 << " " << v2 << endl;
}

方案二:全域/靜態流物件(效能最佳)


ofstream g_ocout; // 全域或靜態

void AddEdge(int v1, int v2) {
    if (!g_ocout.is_open()) g_ocout.open("city.txt", ios::app);
    
    if (v1 == v2) {
        g_ocout << "冗余邊" << v1 << " " << v2 << endl;
        return;
    }
    g_ocout << v1 << " " << v2 << endl;
}

int main() {
    g_ocout.open("city.txt", ios::app); // 程式啟動時開啟一次
    for (int k = 0; k < m; k++) AddEdge(rand()%n, rand()%n);
    g_ocout.close(); // 程式結束前關閉
    return 0;
}

方案三:RAII 包裝類別(現代 C++ 風格)


class EdgeLogger {
    ofstream ofs;
public:
    EdgeLogger(const string& path) : ofs(path, ios::app) {
        if (!ofs) throw runtime_error("無法開啟 " + path);
    }
    void logEdge(int v1, int v2) {
        if (v1 == v2) ofs << "冗余邊 " << v1 << " " << v2 << '\n';
        else ofs << v1 << " " << v2 << '\n';
    }
    ~EdgeLogger() { if (ofs.is_open()) ofs.close(); }
};

// 使用
int main() {
    EdgeLogger logger("city.txt");
    for (int k = 0; k < m; k++) 
        logger.logEdge(rand()%n, rand()%n);
    // 析構函數自動 close()
}

關鍵模式旗標對照表

模式常數行為
截斷(預設)ios::trunc清空檔案、從頭寫入
追加ios::app移至檔案末尾、保留原內容
二進位ios::binary不做換行轉換、適用非文本
讀寫ios::in | ios::out同時支援讀寫、需配合 seekg/seekp

進階:緩衝區控制


// 強制立即寫入磁碟(效能較差但資料安全)
ocout << "重要資料" << endl; // endl 含 flush
ocout.flush(); // 手動刷新

// 或設定無緩衝
ocout.rdbuf()->pubsetbuf(0, 0); // 無緩衝模式

完整修正版主程式


#include 
#include 
using namespace std;

void AddEdge(ofstream& ocout, int v1, int v2) {
    if (v1 == v2) {
        cout << "冗余邊 " << v1 << " " << v2 << endl;
        ocout << "冗余邊 " << v1 << " " << v2 << endl;
        return;
    }
    ocout << v1 << " " << v2 << endl;
}

int main() {
    ofstream ocout("city.txt", ios::app); // 關鍵:追加模式
    if (!ocout) { cerr << "開啟失敗"; return 1; }
    
    for (int k = 0; k < 10; k++) 
        AddEdge(ocout, rand()%5, rand()%5);
    
    ocout.close();
    return 0;
}

除錯技巧

  1. 檢查 `ocout.is_open()` 確認開啟成功
  2. 使用 `ocout.tellp()` 觀察寫入位置
  3. 執行期間用編輯器開啟 `city.txt` 觀察即時內容(部分鎖定可能無法開啟)
  4. 加入 `ocout.exceptions(ofstream::failbit | ofstream::badbit);` 讓失敗拋出異常

掌握文件流模式與生命週期管理,即可避免「只剩最後一次寫入」等經典陷阱,建立穩健的日誌、資料匯出功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved