2010-04-09 66 views
2

將數據發送到fstream時檢查一般錯誤的正確方法是什麼?在fstream輸出操作上執行'catch all'錯誤檢查的正確方法是什麼?

UPDATE:我主要關心的是我聽說過有關輸出和物理寫入硬盤的任何數據之間的延遲。我的假設是,命令「save_file_obj < < save_str」只會將數據發送到某種緩衝區,並且以下檢查「if(save_file_obj.bad())」在確定是否存在操作系統或硬件時不會有任何用處問題。我只是想知道什麼是確定性的「全部捕獲」方式,在執行任何後續操作(如關閉程序)之前,將字符串發送到文件並進行檢查以確定它已寫入磁盤。

我有以下代碼...除了密切似乎是合理的後檢查

int Saver::output() 
{ 
    save_file_handle.open(file_name.c_str()); 
    if (save_file_handle.is_open()) 
    { 
     save_file_handle << save_str.c_str(); 

     if (save_file_handle.bad()) 
     { 
      x_message("Error - failed to save file"); 
      return 0; 
     } 

     save_file_handle.close(); 

     if (save_file_handle.bad()) 
     { 
      x_message("Error - failed to save file"); 
      return 0; 
     } 

     return 1; 
    } 
    else 
    { 
     x_message("Error - couldn't open save file"); 
     return 0; 
    } 
} 

回答

2

一切。這就是說,我會重組的事情略有不同,並拋出一個異常,或使用bool,但是這僅僅是偏好的問題:

 
bool Saver::output() 
{ 
    std::fstream out(_filename.c_str(),std::ios::out); 
    if (! out.is_open()){ 
     LOG4CXX_ERROR(_logger,"Could not open \""<<filename<<"\""); 
     return false; 
    } 

    out << _savestr << std::endl; 
    if (out.bad()){ 
     LOG4CXX_ERROR(_logger,"Could not save to \""<<filename<<"\""); 
     out.close(); 
     return false; 
    } 

    out.close(); 
    return true; 
} 

我還要指出的是,你不需要使用save_str.c_str(),因爲C++ iostreams(包括fstream,ofstream等)都可以輸出std :: string對象。另外,如果在函數的作用域中構造文件流對象,它將在超出作用域時自動關閉。

+0

誰說'save_str'是一個'std :: string'? :p也許這是一個'std :: basic_string <>'在一些自定義的'char_traits'上模板化的,比如不區分大小寫的特徵或者什麼? :p – wilhelmtell 2010-04-10 04:29:47

+0

在這種情況下,它是std :: basic_string Truncheon 2010-04-12 13:35:48

2

您確定save_file_handle尚未與其關聯(打開)文件嗎?如果確實如此,那麼調用其open()方法將失敗,並提高其ios::failbit錯誤標誌 - 如果設置爲此,則會發生任何異常。

close()方法不能失敗,除非文件未打開,在這種情況下,該方法將引發ios::failbit錯誤標誌。無論如何,析構函數應該關閉文件,並且如果save_file_handle是一個堆棧變量,那麼它會自動執行。

int Saver::output() 
{ 
    save_file_handle.open(file_name.c_str()); 
    if (save_file_handle.fail()) 
    { 
     x_message("Error - file failed to previously close"); 
     return 0; 
    } 
    save_file_handle << save_str.c_str(); 

    if (save_file_handle.bad()) 
    { 
     x_message("Error - failed to save file"); 
     return 0; 
    }  
    return 1; 
} 

或者,你可以單獨的錯誤從文件保存邏輯檢查,如果你使用ios::exceptions()

int Saver::output() 
{ 
    ios_base::iostate old = save_file_handle.exceptions(); 
    save_file_handle.exceptions(ios::failbit | ios::badbit); 
    try 
    { 
     save_file_handle.open(file_name.c_str());   
     save_file_handle << save_str.c_str(); 
    } 
    catch (ofstream::failure e) 
    { 
     x_message("Error - couldn't save file"); 
     save_file_handle.exceptions(old); 
     return 0; 
    } 
    save_file_handle.exceptions(old); 
    return 1; 
} 

您可能更願意將呼叫轉移到構造函數save_file_handle.exceptions(ios::failbit | ios::badbit)。然後,您可以擺脫重置異常標誌的語句。

+0

我建議不要在流I/O中使用異常,因爲很少有人會期待流操作拋出,並且因爲使用異常時恢復更加困難。 – 2010-04-09 08:44:46

4

幾點。首先:

save_file_handle 

是C++ fstream實例的一個不好名稱。 fstreams不是文件句柄,所有這些都可以讓讀者感到困惑。其次,邁克爾指出,不需要將C++字符串轉換爲C字符串。唯一一次你應該真正發現自己做這件事的時候,是與C風格的APIS接口​​,以及使用一些設計不佳的C++ API時,(不幸的是)fstream :: open()。

第三,測試流操作是否正常工作的規範方法是測試操作本身。流有一個轉換到void *,這意味着你可以寫這樣的東西:

if (save_file_handle << save_str) { 
    // operation worked 
} 
else { 
    // failed for some reason 
} 

您的代碼應該總是testv流操作,無論是輸入或輸出。

+0

我認爲你的意思是轉換爲布爾,而不是void *。 – 2010-04-11 01:45:43

+0

@Michael我的意思是我說的 - 該標準指定轉換爲void *。 – 2010-04-11 09:24:49

+2

@尼爾,沒關係,你是對的...我一直認爲它是布爾(因爲void *隱式轉換爲布爾)。我從來沒有意識到它實際上是無效的*。這很有趣,你知道他們爲什麼選擇這個習俗嗎?實際上可以對void *對象做任何事情嗎? – 2010-04-11 19:50:11

相關問題