How to create a threadave file without overwriting the existing one?

So far, when I wanted to create a file without overwriting the existing one, I did something like this:

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

But it is not thread safe. So now I am looking for a thread safe version.

Perhaps I can combine some modes to TFileStream.Create(filename, fmCreate +fm???); failed if the file exists?

I need this to associate directory locks with older DOS programs. But DOS programs do not store open files .: - (

+4
source share
2 answers

TFileStream A file-name-based constructor relies on the WIndows CreateFile API call to create a file descriptor that will be used to access the file. The API itself has several parameters, and Create Disposition is especially interesting for you: if you specify CREATE_NEW , the function will fail if the file already exists. You can take advantage of this by calling CreateFile yourself, and then using the return handle to create a TFileStream . You can do this because TFileStream inherits from THandleStream , inherits its descriptor-based constructor, and owns the descriptor (calls CloseHandle in the descriptor you pass to the constructor).

Since this depends on the OS-provided CreateFile function, it will be safe in three modes (without race conditions between FileExists() and the actual creation of the file. It also blocks the old application from accessing the newly created file until you actually close the handle .

 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); 
+7
source

I would save the FileExists check because it handles most cases without relying on exception handling. For borderline cases, you need to handle exceptions in the TFileStream constructor. The second thread trying to create the file should fail if you use it in the shared mode fmShareDenyWrite .

+4
source

All Articles