Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto create threadsave a file without overwriting an existent one?

until now, whenever I wanted to create a file without overwriting an existing one, I've done something like this:

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

But that's not threadsafe. So now I am looking for a threadsafe version.

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

I need this to communicate directory-locks with old DOS programs. But the DOS programs don't hold the files opened. :-(

like image 918
Heinz Z. Avatar asked Dec 22 '22 13:12

Heinz Z.


1 Answers

TFileStream's file-name based constructor relies on the WIndows API call CreateFile to create the file handle that'll be used to access the file. The API itself has multiple parameters, and especially interesting for you is the Create Disposition: if you specify CREATE_NEW, the function fails if the file already exists. You can take advantage of that by calling CreateFile yourself, then using the returned handle to create the TFileStream. You can do that because TFileStream inherits from THandleStream, inherits it's handle-based constructor and owns the handle (calls CloseHandle on the handle you pass to the constructor).

Since this relies on the OS-provided function CreateFile, it'll be trehad-safe (no race condition between FileExists() and actually creating the file. It also blocks the old application from accessing the newly crearted 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);
like image 87
Cosmin Prund Avatar answered May 30 '23 04:05

Cosmin Prund