开发者

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. :开发者_运维百科-(


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


I would keep the FileExists check because it handles most cases without relying on exception handling. For the border cases you have to handle exceptions in TFileStream constructor properly. The second thread trying to create the file should fail if you use it with share mode fmShareDenyWrite.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜