Андрей Игоревич | ↑ |
---|
LoadFromFile() не блокирует файл для записи? |
Смотрим в код
procedure TStrings.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
ответ - да, блокирует
Андрей Игоревич | ↑ |
---|
Делаю так из соображений, что запись происходит в файл крайне редко (раз в десятки минут, гарантированно не чаще), если этот момент пропустить - чтение однозначно будет произведено, чтение однозначно занимает милисекунды. |
Сценарий:
1. Вы вызвали FileIsUse. Файл был свободен.
2. Другая программа заняла файла
3. Вы вызвали ListFile.LoadFromFile(FilePath); и получили исключение.
Андрей Игоревич | ↑ |
---|
И насколько правильно обрабатывать исключения в потоках? Никаких подводных камней? |
Если правильно обрабатывать, то подводных камней нет.
Проблема у вас совсем в другом. Не как открыть файл, а как не поломать пишущую программу. Потому, что если вы откроете эксклюзивно файл, а в это время в этот файл понадобиться что-то записать, то писатель сильно огорчится.
Как я бы решал задачу:
Правильно и универсально - доступ к файлу синхронизирован общим мьютексом. Тогда каждый будет ждать, когда второй файл закроет.
Правильно, но не универсально. Исходим из утверждения
Андрей Игоревич | ↑ |
---|
что запись происходит в файл крайне редко |
Вызвал бы ReadDirectoryChangesW() с маской, скажем FILE_NOTIFY_CHANGE_LAST_WRITE (или FILE_NOTIFY_CHANGE_LAST_ACCESS - нужно смотреть, что будет адекватнее), дождался бы окончания записи и спокойно прочитал бы файл
Не правильно, не универсально, но быстро
Дважды прочитал бы файл без монопольного доступа. Если два раза была считана одна и та же информация - файл прочитан корректно
+ |
type
{$IFDEF UNICODE}
TBuffer = TBytes;
{$ELSE}
TBuffer = string;
{$ENDIF}
function OpenFile(const AName: string): THandle;
begin
Result := CreateFile(
PChar(AName),
GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
end;
function ReadFile(const AName: string): TBuffer;
var
LFile: THandle;
LSize: Cardinal;
LReadSize: Cardinal;
begin
LFile := OpenFile(AName);
while LFile = INVALID_HANDLE_VALUE do begin
Sleep(100);
LFile := OpenFile(AName);
end;
try
LSize := GetFileSize(AFile, nil);
if LSize = INVALID_FILE_SIZE then
RaiseLastOSError;
SetLength(Result, LSize);
Win32Check(ReadFile(AFile, Pointer(Result), LSize, @LReadSize, nil));
if LSize <> LReadSize then
SetLength(Result, LReadSize);
finally
CloseHandle(LFile);
end;
end;
function SameBuff(const ABuf1, ABuf2: TBuffer): Boolean;
begin
Result :=
(Length(ABuf1) = Length(ABuf2)) and
CompareMem(Pointer(ABuf1), Pointer(ABuf2), Length(ABuf1));
end;
procedure LoadToList(const AName: string; AList: TStrings);
var
LBuf1: TBuffer;
LBuf2: TBuffer;
LCurBuf: ^TBuffer;
begin
LBuf1 := ReadFile(AName);
LCurBuf := @LBuf2;
repeat
LCurBuf^ := ReadFile(AName);
if LCurBuf = @LBuf2 then
LCurBuf := @LBuf1
else
LCurBuf := @LBuf2;
until SameBuff(LBuf1, LBuf2);
{$IFDEF UNICODE}
AList.Text := TEncoding.Default.GetString(LBuf1);
{$ELSE}
AList.Text := LBuf1;
{$ENDIF}
end;
|