[Решено] Ошибка "File not open" при чтении файла

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

[Решено] Ошибка "File not open" при чтении файла

Сообщение artem78 » 22.02.2024 21:48:06

Вроде бы тривиальная задача построчного чтения текстового файла.

Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
  F: TextFile;
  Line: String;
begin
  AssignFile(f, FileNameEdit1.FileName);
  try
    Reset(F);
    while not EOF(F) do
    begin
      ReadLn(F, Line);
      ParseLine(line);
    end;
  finally
    CloseFile(f);
  end;
end; 


Но есть одно большое НО: если в этот файл другая программа производит запись данных (файл является логом работы другой программы), то попытка чтения завершится ошибкой "File not open". Хотя тот же самый файл можно без проблем открыть, например, в Notepad++.

Как побороть?
Последний раз редактировалось artem78 23.02.2024 13:16:04, всего редактировалось 1 раз.
artem78
новенький
 
Сообщения: 48
Зарегистрирован: 09.08.2015 18:52:24

Re: Ошибка "File not open" при чтении файла

Сообщение xchgeaxeax » 22.02.2024 21:58:33

Скорее всего дело в запрете на запись у файла лога т.к. он уже открыт.
Попробуйте читать файл через TFileStream или OpenText

ADD: И это не чтение завершается с ошибкой, а Reset. Добавьте проверку IOResult
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: Ошибка "File not open" при чтении файла

Сообщение artem78 » 22.02.2024 22:47:05

xchgeaxeax писал(а):Попробуйте читать файл через TFileStream


Насколько я понимаю, он для двоичных, а не текстовых файлов предназначен. Как с его помощью читать файл построчно мне не понятно.

Добавлено спустя 18 минут 30 секунд:
xchgeaxeax писал(а):OpenText

Что-то не могу найти, в каком юните это.
artem78
новенький
 
Сообщения: 48
Зарегистрирован: 09.08.2015 18:52:24

Re: Ошибка "File not open" при чтении файла

Сообщение iskander » 22.02.2024 23:12:49

artem78 писал(а):Насколько я понимаю, он для двоичных, а не текстовых файлов предназначен. Как с его помощью читать файл построчно мне не понятно.

Посмотрите в сторону TFileReader из модуля StreamEx, который как раз предполагает построчное чтение текстового файла. Что-то вроде
Код: Выделить всё
...
  reader := TFileReader.Create(TextFileName, fmOpenRead or fmShareDenyNone, 4096);
  try
    while not reader.Eof do begin
      line := reader.ReadLine;
      ParseLine(line);
    end;
  finally
    reader.Free;
  end; 
...
iskander
энтузиаст
 
Сообщения: 606
Зарегистрирован: 08.01.2012 18:43:34

Re: Ошибка "File not open" при чтении файла

Сообщение xchgeaxeax » 22.02.2024 23:55:40

artem78 писал(а):Насколько я понимаю, он для двоичных, а не текстовых файлов предназначен. Как с его помощью читать файл построчно мне не понятно.

Понимаю, вручную работать с данными уже не феншуй.
Код: Выделить всё
procedure ParseFile(const aFileName: String);
  function PostInc(var I: LongInt; N: LongInt = 1): LongInt; inline;
  begin
    Result := I;
    I := I + N;
  end;
  function ReadBuff(F: TFileStream; S: LongInt; var B): LongInt;
  begin
    Result := F.Size - F.Position;
    if Result > S then Result := S;
    F.ReadBuffer(B, Result);
  end;
var
  F: TFileStream;
  B: array [0 .. 511] of Char;
  C, I, L: LongInt;
  S: String;
begin
  F := TFileStream.Create(aFileName, fmOpenRead);
  S := '';
  L := 1;
  while F.Position < F.Size do begin
    I := 0;
    C := ReadBuff(F, Length(B), B);
    while I < C do begin
      while (I < C) and (B[I] <> #13) and (B[I] <> #10) do S := S + B[PostInc(I)];
      if I = C then continue;
      if I = 511 then begin
        B[0] := B[I];
        I := 0;
        C := ReadBuff(F, Length(B) - 1, B[1]);
      end;
      if B[I] = #13 then begin
        if B[I + 1] = #10 then inc(I, 2) else inc(I);
      end else if B[I] = #10 then begin
        if B[I + 1] = #13 then inc(I, 2) else inc(I);
      end;
      ParseString(PostInc(L), S);
      S := '';
    end;
  end;
  if Length(S) > 0 then ParseString(S);
  FreeAndNil(F);
end;


Добавлено спустя 59 секунд:
artem78 писал(а):Что-то не могу найти, в каком юните это.

Если у вас Lazarus, тогда это внутренняя функция, которую используют Reset/Rewrite/Append. Она позволяет поиграться с флагами.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: Ошибка "File not open" при чтении файла

Сообщение Alexander » 23.02.2024 07:39:46

Если только чтение, то в любом случае после AssignFile(f, FileNameEdit1.FileName); нужно добавить FileMode := 0;
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 771
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: Ошибка "File not open" при чтении файла

Сообщение Alex2013 » 23.02.2024 09:25:53

artem78 писал(а):
xchgeaxeax писал(а):Попробуйте читать файл через TFileStream


Насколько я понимаю, он для двоичных, а не текстовых файлов предназначен. Как с его помощью читать файл построчно мне не понятно.



Так ясно же читайте "по байтово" и завешайте чение каждой строки по признаку eol (#13#10) для ускорения можно читать поблочно в буфер и парсить на предмет eol уже его.
Зы
Пример от xchgeaxeax скорее всего рабочий но (ИМХО) немного переусложнен.
Зы Зы
Но проблему возможной блокировки файла все это все равно не решает.
Если другая программа тоже написана вами то можно попробовать открывать и закрывать файл для записи каждой строки,а в программе читающей лог добавить чтение каждой строки "с конца" отлеживая увеличение размера файла + пару тройку попыток открытия и чтения.

Добавлено спустя 1 час 5 минут 17 секунд:
Алиса Яндексовна советует .

Можешь подсказать как читать последнюю строку в текстовом файле без перебора всего файла в Лазарус?

В Lazarus, вы можете использовать TStreamReader для чтения текстового файла построчно. Однако, у TStreamReader нет встроенной функции для чтения последней строки без перебора всего файла.
Один из способов сделать это - прочитать файл дважды: сначала прочитать все строки, чтобы узнать количество строк в файле, а затем прочитать последнюю строку, используя индекс этого количества минус единица. Это может быть не очень эффективно, если файл очень большой или если вам нужно читать последнюю строку часто.
Вот пример кода для чтения последней строки файла:
{ Объявляем переменные и инициализируем TFileStream }
var
Stream: TStreamReader;
LastLine: string;
I: Integer;
begin
{ Открываем файл }
Stream := TStreamReader.Create(TFileStream.Create('test.txt', fmOpenRead));
try
{ Считаем количество строк файла }
I := 0;
while Stream.ReadLine <> nil do
begin
Inc(I);
end;

{ Закрываем поток }
Stream.Close;

Хм! Разумеется нам при "индексировании" ( может пригодится при работе с действительно большим файлом) полезно получить не номер строки, а позицию ее начала в файле, но это уже совсем просто...
(С все-же "ИИ это такой ИИ" типичный "джин из сказки" . Спросишь - ответит... Но так что это скорее всего будет почти бесполезно! :wink: ...особенно доставил пассаж про "чтение дважды" (условие Stream.ReadLine <> nil тоже немного сомнительно (там строка на выходе... какой там к черту nil ? )... но что-то полезное в этой подсказки получить все-же можно
TStreamReader действительно существует... https://lazarus-ccr.sourceforge.io/docs ... eader.html )
Последний раз редактировалось Alex2013 23.02.2024 11:13:37, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 3049
Зарегистрирован: 03.04.2013 11:59:44

Re: Ошибка "File not open" при чтении файла

Сообщение xchgeaxeax » 23.02.2024 11:05:22

Alex2013 писал(а):...особенно доставил пассаж про "чтение дважды" ...

С таким подходом Алесе до захвата мира далеко. Мощности не хватит столько лишних действий выполнять.

Сохранить последнюю (там появится nil при чтении файла) и предпоследнюю прочитанную строку - она не догадалась.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: Ошибка "File not open" при чтении файла

Сообщение Alex2013 » 23.02.2024 11:21:08

xchgeaxeax писал(а):Сохранить последнюю (там появится nil при чтении файла) и предпоследнюю прочитанную строку - она не догадалась.

По моему она просто не совсем точно интерпретировала вопрос... (результат работы предложенного кода, номер последней строки )
xchgeaxeax писал(а):С таким подходом Алесе до захвата мира далеко

Да "кутлухочка еще маленькая"... :wink: но это пока...
Последний раз редактировалось Alex2013 23.02.2024 11:54:07, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 3049
Зарегистрирован: 03.04.2013 11:59:44

Re: Ошибка "File not open" при чтении файла

Сообщение xchgeaxeax » 23.02.2024 11:30:47

Попробовал использовать TStreamReader.
Код: Выделить всё
function ParseFile2(const aFileName: String): LongInt;
var
  F: TFileStream;
  R: TStreamReader;
begin
  Result := 1;
  F := TFileStream.Create(aFileName, fmOpenRead);
  R := TStreamReader.Create(F, 4096, False);
  while (not R.Eof) and (ParseLine(R.ReadLine, Result)) do inc(Result);
  FreeAndNil(R);
  FreeAndNil(F);
end;
Код действительно получился короче.
Последний раз редактировалось xchgeaxeax 23.02.2024 12:13:23, всего редактировалось 2 раз(а).
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: Ошибка "File not open" при чтении файла

Сообщение iskander » 23.02.2024 11:58:18

xchgeaxeax писал(а):Как по мне, то лучше использовать буфер для чтения и вручную собирать строки из файлового буфера, находя конец строки.

А что, пример с TFileReader нерабочий?
iskander
энтузиаст
 
Сообщения: 606
Зарегистрирован: 08.01.2012 18:43:34

Re: Ошибка "File not open" при чтении файла

Сообщение xchgeaxeax » 23.02.2024 12:08:48

Поправил на рабочий вариант. Надо было ориентироваться на R.Eof, а не на S.Position

Добавлено спустя 2 минуты 2 секунды:
iskander писал(а):А что, пример с TFileReader нерабочий?

Он менее универсален. Если данные только в файлах, тогда можно использовать его. А если надо взять данные из буфера в памяти? В TStreamReader можно передать TMemoryStream и все будет точно так же.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: Ошибка "File not open" при чтении файла

Сообщение Alex2013 » 23.02.2024 12:13:22

xchgeaxeax писал(а): В конце чтения файла произошла ошибка и последние 100 строк просто не прочитались.

Дык вестимо нужно "окавычить" R.ReadLine через проверку исключения try finally ... + перед каждым чтением провеять что F.Position <> F.Size. Да и IOResult возможно поверить лишним не будет.
Зы
Код действительно получился короче.
...
Код: Выделить всё
function ParseFile2(const aFileName: String): LongInt;
var
  F: TFileStream;
  R: TStreamReader;
begin
  Result := 1;
try
  F := TFileStream.Create(aFileName, fmOpenRead);
  R := TStreamReader.Create(F, 4096, False);
  while (not R.Eof) and (ParseLine(R.ReadLine, Result)) do inc(Result);
finally
  FreeAndNil(R);
  FreeAndNil(F);
end
end;


О вот так действительно более похоже на правду..
Последний раз редактировалось Alex2013 23.02.2024 12:31:01, всего редактировалось 4 раз(а).
Alex2013
долгожитель
 
Сообщения: 3049
Зарегистрирован: 03.04.2013 11:59:44

Re: Ошибка "File not open" при чтении файла

Сообщение iskander » 23.02.2024 12:15:22

xchgeaxeax писал(а):Он менее универсален. Если данные только в файлах, тогда можно использовать его. А если надо взять данные из буфера в памяти? В TStreamReader можно передать TMemoryStream и все будет точно так же.

А вопрос-то в топике был о чём?
iskander
энтузиаст
 
Сообщения: 606
Зарегистрирован: 08.01.2012 18:43:34

Re: Ошибка "File not open" при чтении файла

Сообщение artem78 » 23.02.2024 12:16:48

Alexander писал(а):Если только чтение, то в любом случае после AssignFile(f, FileNameEdit1.FileName); нужно добавить FileMode := 0;

Не помогло. Та же ошибка.

iskander писал(а):Посмотрите в сторону TFileReader из модуля StreamEx, который как раз предполагает построчное чтение текстового файла.

Зато этим способом с флагами fmOpenRead or fmShareDenyNone работает как надо. Большое спасибо!

xchgeaxeax писал(а):Понимаю, вручную работать с данными уже не феншуй.

А смысл "изобретать велосипед", когда "из коробки" уже есть то что нужно?

xchgeaxeax писал(а): iskander писал(а):
А что, пример с TFileReader нерабочий?


Он менее универсален. Если данные только в файлах, тогда можно использовать его.

Для моих нужд вполне достаточно. Из памяти мне не нужно, только из файла.
artem78
новенький
 
Сообщения: 48
Зарегистрирован: 09.08.2015 18:52:24

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 21

Рейтинг@Mail.ru