• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 465
  • Last Modified:

check if a file is open / inuse

I tried to check if a file is open or inuse, if file is used wait eg. 10 sec for the file to become free again, what is wrong with my code ???
function WaitForFileInUse (const fName: TFileName; TimeToWait : Integer): Boolean;
Var     Zeit1, Zeit2, Differenz  : TDateTime;
        FileReady                : Boolean;
begin
      Zeit1 := now;

      repeat

       Zeit2 := now;

       FileReady := not IsFileInUse(fName);

       result := Fileready;

      until ((SecondsBetween (zeit2, zeit1) > TimeToWait)  or (FileReady = true));

end;


/// **************************************************************************
///  http://www.delphipraxis.net/topic159650_erkennen+ob+eine+datei+gerade+benutzt+wird.html&highlight=isfileinuse
///  http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
/// **************************************************************************
function IsFileInUse(const fName: TFileName): Boolean;
var HFileRes: HFILE;
begin
  if not FileExists(fName) then
  begin
    Result := false;
    Exit;
  end;

  HFileRes := CreateFile(PChar(fName),
                         GENERIC_READ or GENERIC_WRITE,
                         0,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
  Result := (HFileRes = INVALID_HANDLE_VALUE);
  if not Result then  CloseHandle(HFileRes);
end;

Open in new window

0
BdLm
Asked:
BdLm
  • 3
  • 2
  • 2
1 Solution
 
Geert GOracle dbaCommented:
are you sure the file ever get's released ?
i tend to run into files which are in use for a few months ... like database files
0
 
TheRealLokiSenior DeveloperCommented:
A couple of things
Firstly, you need to move the second function "above" the first one, since it is called.
Secondly, you have not set the "result" of the "WaitForFileInUse" function

If that all false, I have included 2 replacement functions that work here (commented out)




/// **************************************************************************
///  http://www.delphipraxis.net/topic159650_erkennen+ob+eine+datei+gerade+benutzt+wird.html&highlight=isfileinuse
///  http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
/// **************************************************************************
function IsFileInUse(const fName: TFileName): Boolean;
var HFileRes: HFILE;
begin
  if not FileExists(fName) then
  begin
    Result := false;
    Exit;
  end;

  HFileRes := CreateFile(PChar(fName),
                         GENERIC_READ or GENERIC_WRITE,
                         0,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
  Result := (HFileRes = INVALID_HANDLE_VALUE);
  if not Result then  CloseHandle(HFileRes);
end;


function WaitForFileInUse (const fName: TFileName; TimeToWait : Integer): Boolean;
Var     Zeit1, Zeit2, Differenz  : TDateTime;
        FileReady                : Boolean;
begin
      Zeit1 := now;
      repeat

       Zeit2 := now;

       FileReady := not IsFileInUse(fName);

       result := Fileready;

      until ((SecondsBetween (zeit2, zeit1) > TimeToWait)  or (FileReady = true));
      result := FileReady; // NEEDED
end;

{ REPLACEMENT FUNCTIONS THAT DEFINITELY WORK HERE

function IsFileInUse(const fName: TFileName): Boolean;
var
  FS: TFileStream;
begin
  result := false; // default
  if not FileExists(fName) then
    result := false
  else
  begin
    try
      FS := TFileStream.Create(fName, fmOpenReadWrite	 + fmShareExclusive);
      result := false;
      FS.Free;
    except
      result := true;
    end;
  end;
end;

function WaitForFileInUse (const fName: TFileName; TimeToWait : Integer): Boolean;
const
  RetryDelay = 100; // milliseconds delay before each retry
Var
  GiveUpTime: TDateTime;
begin
  result := false; // default
  GiveUpTime := Now + EncodeTime(0, 0, TimeToWait, 0);
  while ((not result) and (Now < GiveUpTime)) do
  begin
    result := not IsFileInUse(fName);
    if (not result) then sleep(RetryDelay);
  end;
end;
}

Open in new window

0
 
BdLmAuthor Commented:
i'm debugging a multi thread application, from here I#m writting to a debug / speed profiling file,  somethime my application stops with "Can't  write to the debugging file".

@TheRealLoki:    thks for the code , open a file with IE or Notepad, the file does not get access protected, the function returns WaitForFileInUse  "file is free"

@Geert: file type is xml.


won't spend much effort on this topic (eg. change the thread class) as it is just for debug and code analysis
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
Geert GOracle dbaCommented:
just my 2 cents:

xml is a very slow type of file for logging
you allways need to remove the closing piece and then add it again

it will slow down your logging

better to just log with append

and then use a other tool to nicely display the log entries
0
 
Geert GOracle dbaCommented:
you a logging ?
this a bit more than what you want, but not in xml:
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_24711546.html#25273004

it does 3 attempts to write to the file
you could add a infinite loop to make sure you have logging
0
 
TheRealLokiSenior DeveloperCommented:
@TheRealLoki:    thks for the code , open a file with IE or  Notepad, the file does not get  access protected, the function returns WaitForFileInUse   "file is free"
That's actually correct, because you "can" write to the log file if it is opened in notepad
a better way to test is to right click the file and choose properties. click "read only" and "apply"

I do lots of multithread logging to the same /different files and had to recently change 1 routine

I used to use assignfile, reset/rewrite, but had neglected the share mode (filemode = 64, etc)
I can almost guarantee that you can solve your issue by changing your log writing routine and doing the "file in use" check in the SAME routine
i.e. whatever file handle you create as opening to "test" file in use, you KEEP that handle and use it to write...

Keep actual writes to as fast as possible, and it's ok to open and close the file each time
Remember, if you're not using a "share mode" then just reading the log with (some, not necessarily notepad) viewers can lock the file.
Something as simple as this log method will most likely work :-
(sorry, away from dev pc atm so excuse typos in it, but it's mostly identical to my threaded log routiness I use in commercial apps)

procedure WriteLog(filename_: string; s: string);
const
  retrymax = 3;
var
  FS: TFileStream;
  retries: integer;
  OutS: ansistring;
begin
  retries := retrymax;
  repeat
    try
      if FileExists(filename_) then
        FS := TFileStream.Create(filename_, fmOpenReadWrite OR fmShareDenyWrite)
      else
        FS := TFileStream.Create(filename_, fmCreate);
      try
        OutS := S + #13#10;
        FS.Write(S[1], length(s));
        retries := 0; // flag that it worked....
      finally
        FS.Free;
      end;
    except
      on e: exception do
      begin
        sleep(10); // up to you if you want to delay
        dec(retries);
        if (retries = 0) then  OutputDebugString(PChar('Error writing Log: ' + S)); // give up, write to debug log and exit
      end;
  until retries = 0;

end;

Open in new window

0
 
BdLmAuthor Commented:
actually I#m writing inside a thread, the code does not solve my problem behind but the code is fine,

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now