Search code examples
delphifile-renamedelphi-10.2-tokyo

Access denied in RenameFile after FileExists


I´m regularly importing files from a path into an application with Delphi 10.2. After each successful import I want to move the current file to a new path(SuccessPath). It´s possible to have file names that already exist in the SuccessPath. That´s why I first check if the file name exists. If thats the case I append an index to the filename (e.g. test.txt changes to test_2.txt).

In some cases RenameFile returns false and GetLastError returns Access denied. It´s probably an unclosed file handle. Do I need to close a handle after calling FileExists? How would I do so?

Here´s my example code:

procedure TDemo.Execute;
begin
  MoveFileWithRenameDuplicates('C:\temp\test.txt', 'C:\temp\new\');
end;

procedure TDemo.MoveFileWithRenameDuplicates(oldFile, newPath: string);
var
  lNewFile: string;
  i: integer;

begin
  lNewFile := newPath + TPath.GetFileName(oldFile);
  i := 0;
  repeat
    if FileExists(lNewFile) then
    begin
      i := i + 1;
      lNewFile := newPath + TPath.GetFileNameWithoutExtension(oldFile) + '_' + IntToStr(i) + TPath.GetExtension(oldFile);
    end;
  until not FileExists(lNewFile);
  WriteLn('lNewFile=' + lNewFile);

  if not RenameFile(oldFile, lNewFile) then
    WriteLn(SysErrorMessage(GetLastError));
end;

Solution

  • I changed my loop like Remy suggested. I also realized that the appended index didn´t actually increment so I changed that aswell:

    procedure TDemo.MoveFileWithRenameDuplicates(oldFile, newPath: string);
    var
      lNewFile: string;
      i: integer;
     
    begin
        lNewFile := newPath + TPath.GetFileName(oldFile);
        i := 0;
        while not RenameFile(oldFile, lNewFile) do
        begin
            if FileExists(lNewFile) then
            begin
              lNewFile := newPath
                + TRegEx.Match(TPath.GetFileNameWithoutExtension(oldFile), '/^(?''name''[^_]*)_\d*$', [roIgnoreCase]).Groups['name'].Value
                + '_' + IntToStr(i) + TPath.GetExtension(oldFile);
            end
        else
            begin
              WriteLn(SysErrorMessage(GetLastError));
              break;
            end;
        end;
    end;
    

    This seems to have fixed my problem.