2011-05-30 133 views
4

直到現在,每當我想而不覆蓋現有的創建一個文件,我已經做了這樣的事情:如何在不覆蓋現有文件的情況下創建線程文件?

if not FileExists(filename) then 
    stream := TFileStream.Create(filename, fmCreate); 

但是,這不是線程安全的。所以現在我正在尋找一個線程安全版本。

也許我可以結合一些模式,使TFileStream.Create(filename, fmCreate +fm???);失敗,如果文件存在?

我需要這個來與舊的DOS程序進行目錄鎖的通信。但DOS程序不保存打開的文件。 :-(

+0

執行DOS程序有鎖定文件也?使Delphi應用程序線程安全不會讓DOS程序線程安全的。而且我們不是在談論線程,但有關進程在這裏。你確定你正在處理DOS程序,而不是Win32命令行程序嗎?爲了確保我們給你一個可行的解決方案,我們需要更多地瞭解你的ar的「DOS程序」部分結構:他們是如何工作的?哪個應用正在鎖定目錄?你使用哪種狀態機進行鎖定? – 2011-05-30 11:51:24

+0

你說的這個DOS是什麼?你在Windows 98上運行嗎? – 2011-05-30 16:01:31

+0

@David,AFAIK你可以在所有32位版本的Windows上運行DOS程序,包括Windows 7 32位;無需Windows 98! – 2011-05-30 19:06:25

回答

7

TFileStream的基於文件名的構造函數依賴於Windows API調用CreateFile創建的文件處理這個會被用來訪問文件。該API本身有多個參數,尤其是有趣的是創建處置:如果您指定CREATE_NEW,則該函數失敗如果該文件已經存在。您可以自己調用CreateFile,然後使用返回的句柄創建TFileStream。你可以這樣做,因爲TFileStream繼承自THandleStream,繼承它的基於句柄的構造函數並擁有句柄(在傳遞給構造函數的句柄上調用CloseHandle)。

因爲這依賴於操作系統提供的功能CreateFile,它會被trehad安全(FileExists()和實際創建文件之間沒有競爭條件,同時也阻止訪問新crearted文件,直到你真正接近舊的應用程序手柄。

var FH: NativeUInt; 

// ... 

    FH := CreateFile('FileName', GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_NEW, 0, 0); 
    if FH = INVALID_HANDLE_VALUE then 
    begin 
    // Creating the new file failed! I'm raizing an exception, but you can do something 
    // better-suited for your case, like trying a new file name. 
    RaiseLastOSError; 
    end; 
    // Create the stream using the prepared Handle 
    HS := TFileStram.Create(FH); 
+0

這是更優雅的解決方案,用於實現跨流程文件創建。但我發現這個問題令人困惑:那些「DOS程序」是關於什麼的?鎖定工作如何?您的解決方案不適用於DOS程序,但只適用於Win32 Delphi程序。 – 2011-05-30 11:54:22

+0

@ A.Bouchez,我希望該解決方案也可以在DOS程序中使用,因爲它會發生在操作系統級別;不幸的是,我不再有任何DOS程序的痕跡來測試! – 2011-05-30 12:15:33

+0

@Cosmin CreateFile API是一個Win32 API,而不是DOS API。如果DOS程序只是期望*鎖定文件*存在於磁盤上並由Delphi創建,那麼通過刪除該文件來釋放鎖定,它將起作用。但是,如果DOS程序也需要鎖定文件,如果它不遵循與CreateFile調用相同的方案,它將不起作用。這就是爲什麼我要求更多關於這些「DOS程序」的細節...... – 2011-05-30 13:00:24

4

我會保持FileExists檢查,因爲它可以處理大多數情況下,不依賴於異常處理。因爲你必須妥善處理TFileStream構造異常邊界的情況下,第二個線程試圖創建的文件應該失敗,如果你與共享模式fmShareDenyWrite使用它。

相關問題