Переименование файла в событии TTimer выдает ошибку

Смотрите шаги ниже, как воспроизвести. Я использую Delphi 10.1 Berlin и Windows 10 и компилирую в win32.

  1. Создать новое приложение VCL Forms
  2. Поместите TTimer и TMemo в форму
  3. Установите интервал таймера на 10 мс
  4. Поместите этот код в событие OnTimer:
if FileExists('named.txt') then
begin
  Memo1.Lines.Add('named.txt exists');
  DeleteFile('renamed.txt');  //delete if it exists
  if RenameFile('named.txt', 'renamed.txt') then
    Memo1.Lines.Add(' renamed OK')
  else
    Memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
end;
  1. Запустите программу

  2. Создайте файл с именем.txt

Вывод TMemo показывает:

named.txt существует
 переименован ОК
  1. Теперь переименуйте файл renamed.txt обратно в named.txt в проводнике.

Вывод TMemo теперь показывает:

named.txt существует
 переименован ОК
named.txt существует
 переименован ОК

Но появится сообщение об ошибке "Файл или папка не существует". Почему?

(Renamefile возвращает ОК).

Установка интервала таймера, например, 500 мс, кажется приемлемой (сообщение об ошибке отсутствует).

Вот сообщение (на шведском):

Я даже скопировал exe-файл на другой компьютер с тем же результатом:

2 ответа

Я испытывал ту же проблему,

Во-первых, похоже, что это не имеет отношения к вашему коду.

Из того, что я выяснил, ошибка является ошибкой Windows и возникает, когда вы пытаетесь переименовать файл еще раз до того, как первый процесс переименования (из Windows) завершен должным образом, поэтому процесс переименования delphi мог завершиться, и ваш код продолжается (и запускается). другое переименование), но переименование окон еще не завершено должным образом.

Та же проблема возникает, когда вы используете разные языки программирования, например, с командным файлом:

:loop
    ren named.txt renamed.txt
goto loop

вы получаете то же сообщение об ошибке.

Чтобы решить вашу проблему, единственное, о чем я могу думать, это увеличить задержку таймера, как вы предложили в своем посте.

Я надеюсь, это помогло, и я очень извиняюсь, я могу решить вашу проблему

Я предполагаю, что одна из строк в событии таймера в конечном итоге вызывает Application.ProcessMessages (возможно, добавление в свойство Memo.Lines). Если с момента, когда таймер начал выполнять событие, прошло более 10 мсек, в очереди сообщений будет ожидаться новое событие таймера, которое снова вызовет вызов события.

По сути, вы затем выполняете операторы по следующим направлениям:

  if FileExists('named.txt') then
  begin
    memo1.Lines.Add('named.txt exists');
    // Embedded ProcessMessages at some point leads to
    // the timer event being called again
    if FileExists('named.txt') then
    begin
      DeleteFile('renamed.txt');  //delete if it exists
      if RenameFile('named.txt', 'renamed.txt') then
        memo1.Lines.Add(' renamed OK')
      else
        memo1.Lines.Add(' rename failed with error : '+IntToStr(GetLastError));
    end;
    // Nested Timer Event could end here,
    // which returns execution to the outer event
    DeleteFile('renamed.txt');  //delete if it exists
    // The named.text file does not exist anymore - renamed away 7 lines above
    if RenameFile('named.txt', 'renamed.txt') then
      memo1.Lines.Add(' renamed OK')
    else
      memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
  end;
  // Original Timer event ends here...

Одним из решений будет следующее:

Timer.Enabled := False;
try
  if FileExists('named.txt') then
  begin
    memo1.Lines.Add('named.txt exists');
    DeleteFile('renamed.txt');  //delete if it exists
    if RenameFile('named.txt', 'renamed.txt') then
      memo1.Lines.Add(' renamed OK')
    else
      memo1.Lines.Add(' rename failed with error : '+ IntToStr(GetLastError));
  end;
finally
  Timer.Enabled := True
end;

чтобы убедиться, что никакие новые события таймера не могут произойти во время их обработки.

Другие вопросы по тегам