Question

Im attempting to write to a network share (local) using TFilestream. It all works fine should the network connection not be interupted.

However, if I pull the network cable and then reconnect it, subsequent attempts to open the filestream fail due to access restrictions. I also cannot even delete the file in explorer! It appears TFilestream locks the file and the only way to get around this is to reboot.

In my application, I keep the file open the whole time I am writing to it (it is a log file written once every second).

My code which fails is below:

procedure TFileLogger.SetLogFilename(const Value: String);
var line : String;
Created : Boolean;
begin
  if not DirectoryExists(ExtractFilePath(Value)) then //create the dir if it doesnt exist
  begin
       try
         ForceDirectories(ExtractFilePath(Value));
       except
         ErrorMessage(Value); //dont have access to the dir so flag an error
         Exit;
       end;
  end;
  if Value <> FLogFilename then //Either create or open existing
  begin
      Created := False;          
      if Assigned(FStream) then
         FreeandNil(FStream);
      if not FileExists(Value) then   //create the file and write header
      begin
           //now create a new file
           try
              FStream := TFileStream.Create(Value,fmCreate);
              Created := True;
           finally
             FreeAndNil(FStream);
           end;
           if not Created then //an issue with creating the file
           begin
                ErrorMessage(Value);
                Exit;
           end;
           FLogFilename := Value;
           //now open file for writing
           FStream := TFileStream.Create(FLogFilename,fmOpenWrite or fmShareDenyWrite);
           try
              line := FHeader + #13#10;
              FStream.Seek(0,soFromEnd);
              FStream.Write(Line[1], length(Line));
              FSuppress := False;
           except
              ErrorMessage(Value);  
           end;
      end else begin //just open it
           FLogFilename := Value;
           //now open file for writing
           FStream := TFileStream.Create(FLogFilename,fmOpenWrite or fmShareDenyWrite); //This line fails if the network is lost and then reconnected
      end;
  end;
end;

If anyone has any advice it would be appreciated.

Was it helpful?

Solution

Try to close your file using Network Share API, namely NetFileEnum and NetFileClose functions. See also a related question

OTHER TIPS

I do something similar, but don't use TFileStream. I use file methods from SysUtils. Here is basically what I do, adapted to your situation:

// variables used in pseudo-code below
var
  fHandle, bytesWriten: Integer;
  Value: string;
  • Open the output file using fHandle := FileOpen('filename', fmOpenReadWrite or ...).
  • Verify is fHandle > -1, sleep and loop if it isn't.
  • Write the output bytesWritten := FileWrite(fHandle, Value, Length(Value));.
  • Check the bytesWritten, they should = Length(Value).
  • If the bytesWritten are 0, you know the file handle was lost. I put a try ... finally block around all my code and execute if fHandle > -1 then try FileClose(fHandle); except end; so that it forces the system to release the file handle, even if the file is no longer accessible.
  • If the bytesWritten was 0, then sleep for a few seconds and try again.

It seems like I had a similar issue as you describe until I added the code:

if fHandle > -1 then
  try
    FileClose(fHandle);
  except
  end;

I have copied gigabyte files to a remote (slow) network share using this approach, and the network share has been lost several times during the copy. I am able to resume the copy as soon as the network share is available again. You should be able to do something similar with your log file...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top