2012-06-22 49 views
2

我的代碼看起來接近該:競爭條件

  1. 大量使用普通的C++ IO流插入的寫操作的像steram << "foo";
  2. stream.flush();在一些點;
  3. MSVC C API的_stat()在上面刷新後調用。

我所觀察到的是,_stat()調用返回的大小從stream.tellp()不同,尺寸較小。

如果我在調用_stat()函數之前關閉stream,它會返回正確的結果。我已經步入_stat(),它使用FindFirstFileEx()來獲得大小。

這是一個已知的Win32 API quirk嗎?

+2

是否有可能stream.flush()是異步的,並在緩衝區刷新之前返回? –

+0

您應該通過FileMon檢查,哪些操作是由您的呼叫執行的。如果偶然使用FASTIO_WRITE而不是IRP_MJ_WRITE,那麼您的代碼將隱式使用FASTIO的中間緩衝區。也許你可以通過編程實現對IRP的回退,但這會減慢寫入過程。 – Stan

+3

這是爲NTFS文件系統而設計的,而不是api怪癖。在關閉文件的所有句柄之前,目錄記錄中的屬性不反映實際的文件屬性。不僅僅是文件大小,還有時間戳值。 –

回答

2

我假設您正在使用Windows Vista或更高版本。每次將文件刷新到光盤時,文件大小在XP下的文件屬性中都會更新。在Vista上,這不再是正確的,因爲漢斯已經評論過文件屬性,並且在關閉文件的最後一個句柄時更新了它的大小。

查看Old New Thing Blog瞭解更多詳情。

您可以嘗試第二次打開文件並關閉它。

+0

感謝您訪問博客的鏈接。它解釋了很多事情。儘管在我看來這是'_stat()'中的一個錯誤,那麼它使用的函數可能會讓我失去數據。 – wilx

+0

這不是唯一的怪癖。 Windows具有稱爲文件系統隧道的功能,它在相當長的時間內報告相同的文件大小。例如,如果你是登錄到文件,關閉,重命名並再次打開具有相同名稱的文件。見http://blogs.msdn.com/b/oldnewthing/archive/2005/07/15/439261.aspx –

+0

呃。這看起來像無理取悅懶惰或糟糕的編碼者。如果我希望文件具有相同的時間戳,我會自己處理。 – wilx

0

這可能是由於文件系統緩存。從C++流的角度來看,它已按照標準的要求將所有寫入數據傳遞到物理設備。但文件系統可能會緩存寫入,並根據其他策略刷新它們。

一個可能的解決辦法是在以下Win32 API的選項使用:

  1. 如果你碰巧自己打開文件,使用CreateFile,使用FILE_FLAG_NO_BUFFERINGFILE_FLAG_WRITE_THROUGH標誌。
  2. 編寫完成後,請致電FlushFileBuffers以確保元數據已刷新(您必須以某種方式獲取該文件的句柄)。

這應該不會損害性能太多,假設您的C++流正在做自己的緩衝。

+0

系統不應該確保其內部數據結構之間的一致性嗎?我實際上重做了代碼,以便它在'_stat()'調用之前執行'stream.close()',現在它可以工作。 – wilx

+0

@wilx,一致性是有代價的。如果不確保一致性,高速緩存運行得更好,因此您應該對自己的應用程序說哪一個更重要。我很高興你解決了你的問題,看看我的建議是否能解決問題也會很有趣。 – eran

+0

當然,一致性和正確性比速度更重要。 – wilx

1

使用GetFileInformationByHandle獲取確切的大小。