Переименование файла в событии TTimer выдает ошибку
Смотрите шаги ниже, как воспроизвести. Я использую Delphi 10.1 Berlin и Windows 10 и компилирую в win32.
- Создать новое приложение VCL Forms
- Поместите TTimer и TMemo в форму
- Установите интервал таймера на 10 мс
- Поместите этот код в событие 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;
Запустите программу
Создайте файл с именем.txt
Вывод TMemo показывает:
named.txt существует переименован ОК
- Теперь переименуйте файл 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;
чтобы убедиться, что никакие новые события таймера не могут произойти во время их обработки.