Delphi writing to a network share using TFilestream locks the file when network is lost
-
27-06-2021 - |
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.
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
are0
, you know the file handle was lost. I put atry ... finally
block around all my code and executeif 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
was0
, 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...