Конференция "Начинающим" » Что не так с этой простой процедурой?
 
  • IGray (13.11.17 03:25) [0]
    Мне в программе нужно удалить папку с файлами. Процедура которую приведу ниже при вызове в конкретном месте программы приводит к странному эффекту - при просмотре фаром папка не пропадает но войти в неё невозможно - фар выдаёт "Access denied", но если выйти из программы - то папка наконец пропадает. Пробовал вместо вызова этой процедуры удалить папку (в этот момент) фаром - получается, т.е. реально ничто в папке удалению не мешает. Вроде выходит что проблема в процедуре, но не могу понять какая.. Взгляните, пожалуйста!

    На то, что в процедуре отсутствует контроль ошибок прошу внимание не обращать, т.к. похоже дело не в этом раз фаром всё удаляется..

    procedure DeleteFolder(const aFolder: String);
    var
     Found: TSearchRec;
    begin
       Found.Name := '';

       if FindFirst(aFolder + '\*.*', faAnyFile, Found) = 0 then
       begin          // Пройдем по всем файлам и папкам
         repeat
           if (Found.Name <> '.') and (Found.Name <> '..') then
             if (Found.Attr and faDirectory) <> 0 then   // Удалим вложенную папку - рекурсия
               DeleteFolder ( aFolder + '\' + Found.Name )
             else                               // Удалим файл
               DeleteFile ( aFolder + '\' + Found.Name );
         until FindNext(Found) <> 0;

         FindClose(Found);
       end;

       if DirectoryExists(aFolder) then
         RemoveDir ( aFolder );  // Удалим саму папку
    end;  // of TDBTools.DeleteFolder
  • KilkennyCat © (13.11.17 05:46) [1]
    TDirectory.Delete
  • rrrrrr © (13.11.17 08:38) [2]
    при вызове в конкретном месте программы

    в этом конкретном месте программы каррентдир процесса мешает удалению папки.
  • Юрий Зотов © (13.11.17 10:29) [3]
    А еще надо исключить возможность утечки памяти:

    if FindFirst... then
    try
     repeat
       ...          
     until FindNext...
    finally
     FindClose...
    end
  • IGray (13.11.17 12:30) [4]
    TDirectory.Delete

    Сорри, забыл указать, что работаю на Delphi 2007, так что это для меня не вариант.. А в чём, любопытно, преимущество этой функции?

    в этом конкретном месте программы каррентдир процесса мешает удалению папки.

    Удаляемая папка лежит далеко в стороне от процесса.. Не текущая.
    Так что вопрос пока в силе ((

    Всем спасибо за ответы!
  • RemoveDir (13.11.17 14:35) [5]
    D5, проблем не обнаружено. Просмотрел Total Commander-ом. Кстати как просматривается "удаленная" папка проводником. Мало вероятно, но не исключено, что это что-то с Far-ом. Давно юзаю TC.
  • RemoveDir (13.11.17 14:37) [6]
    > Кстати как просматривается "удаленная" папка проводником???

  • IGray (13.11.17 14:49) [7]
    не исключено, что это что-то с Far-ом

    Проводник тоже выдаёт "Access denied"
  • IGray (13.11.17 14:52) [8]
    Повторюсь - после закрытия программы папка таки пропадает
  • rrrrrr © (13.11.17 15:12) [9]
    можно до утра мечтать про единорогов и камлать на процедуры, которые "действуют по особому" только "в конкретных местах программы"

    но утром все равно обнаружится, что в программе есть оупендиалог с выключенной ofNoChangeDir и все дело было в текущем каталоге процесса, который и мешал удалению папки.
  • QAZ © (13.11.17 15:16) [10]
    The RemoveDirectory function marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed.

    To recursively delete the files in a directory, use the SHFileOperation function.
  • IGray (13.11.17 15:24) [11]
    с выключенной ofNoChangeDir и все дело было в текущем каталоге процесса, который и мешал удалению папкино если б что-то блокировало, тоя ведь и фаром удалить бы не смог, так?

    И похоже дело всё в процедуре, так как (хорошая новость!) я таки нашёл в инете нармально работающую аналогичную, но проблема в том, что я так и не понял пока в чём там ключевое отличие и зачем там атрибуты файлов меняются. Привожу текст полностью, может вам удастся увидеть:

    { **** UBPFD *********** by delphibase.endimus.com ****
    >> Удаление непустого каталога вместе с подкаталогами

    Удаление подкаталогов рекурсивное - функция вызывает саму себя.
    Описание назначения агрументов:

    -DeleteAllFilesAndFolder - если TRUE то функцией будут предприняты
    попытки для установки атрибута faArchive любому файлу или папке
    перед его(её) удалением;

    -StopIfNotAllDeleted - если TRUE то работа функции моментально
    прекращается если возникла ошибка удаления хотя бы одного файла или папки;

    -RemoveRoot - если TRUE, указывает на необходимость удаления корня.

    Зависимости: FileCtrl, SysUtils
    Автор:       lipskiy, lipskiy@mail.ru, ICQ:51219290, Санкт-Петербург
    Copyright:   Собственное написание (lipskiy)
    Дата:        26 апреля 2002 г.
    ***************************************************** }


    function FullRemoveDir(Dir: string; DeleteAllFilesAndFolders,
                          StopIfNotAllDeleted, RemoveRoot: boolean): Boolean;
    var
     i: Integer;
     SRec: TSearchRec;
     FN: string;
    begin
     Result := False;
     if not DirectoryExists(Dir) then
       exit;
     Result := True;
     // Добавляем слэш в конце и задаем маску - "все файлы и директории"
     Dir := IncludeTrailingBackslash(Dir);
     i := FindFirst(Dir + '*', faAnyFile, SRec);
     try
       while i = 0 do
       begin
         // Получаем полный путь к файлу или директорию
         FN := Dir + SRec.Name;
         // Если это директория
         if SRec.Attr = faDirectory then
         begin
           // Рекурсивный вызов этой же функции с ключом удаления корня
           if (SRec.Name <> '') and (SRec.Name <> '.') and (SRec.Name <> '..') then
           begin
             if DeleteAllFilesAndFolders then
               FileSetAttr(FN, faArchive);
             Result := FullRemoveDir(FN, DeleteAllFilesAndFolders,
               StopIfNotAllDeleted, True);
             if not Result and StopIfNotAllDeleted then
               exit;
           end;
         end
         else // Иначе удаляем файл
         begin
           if DeleteAllFilesAndFolders then
             FileSetAttr(FN, faArchive);
           Result := SysUtils.DeleteFile(FN);
           if not Result and StopIfNotAllDeleted then
             exit;
         end;
         // Берем следующий файл или директорию
         i := FindNext(SRec);
       end;
     finally
       SysUtils.FindClose(SRec);
     end;
     if not Result then
       exit;
     if RemoveRoot then // Если необходимо удалить корень - удаляем
       if not RemoveDir(Dir) then
         Result := false;
    end;

  • IGray (13.11.17 15:32) [12]
    The RemoveDirectory function marks a directory for deletion on close

    Я использую RemoveDir - другую функцию.
  • Inovet © (13.11.17 15:53) [13]
    > [12] IGray   (13.11.17 15:32)
    > Я использую RemoveDir - другую функцию.

    Открываем исходник и видим:
    function RemoveDir(const Dir: string): Boolean;
    {$IFDEF MSWINDOWS}
    begin
     Result := RemoveDirectory(PChar(Dir));
    end;
    {$ENDIF MSWINDOWS}


    Далее открываем MSDN и читаем:
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx
  • Inovet © (13.11.17 15:55) [14]
    Перед вызовом в проблемном месте вставить

    ShowMessage(GetCurrentDir);

  • IGray (13.11.17 16:47) [15]
    Открываем исходник и видим:
    Хм.. А в дельфийском хелпе ни намёка на то, что удаление может быть отложено.. Спасибо! Но прикол в том, что приведённая выше работающая функция использует ту же самую RemoveDir
    Но там она удаляет всё сразу.

    Перед вызовом в проблемном месте вставить
    ShowMessage(GetCurrentDir);

    Выдаёт папку экзешника, которая далеко в стороне, разве что на одном диске.
  • QAZ © (13.11.17 16:59) [16]

    > Хм..

    тебеж написали где нужно брать инфу по винде...
    FILE_ATTRIBUTE_ARCHIVE - A file or directory that is an archive file or a directory. Applications use this attribute to mark files for backup or removal.
  • IGray (13.11.17 20:52) [17]
    Закоментировал в приведённой выше работающей функции строчки, меняющие атрибуты - всё равно работает, собака.. Видимо, в данном случае дело всё-таки не в атрибутах..
  • Styx © (14.11.17 00:45) [18]
    А так?

    procedure DeleteFolder(const aFolder: String);
    var
    Found: TSearchRec;
    begin
      Found.Name := '';

      if FindFirst(aFolder + '\*.*', faAnyFile, Found) = 0 then
      begin          // Пройдем по всем файлам и папкам
        repeat
          if (Found.Name <> '.') and (Found.Name <> '..') then
            if (Found.Attr and faDirectory) <> 0 then   // Удалим вложенную папку - рекурсия
              DeleteFolder ( aFolder + '\' + Found.Name )
            else                               // Удалим файл
              DeleteFile ( aFolder + '\' + Found.Name );
        until FindNext(Found) <> 0;

      end;
      FindClose(Found);

      if DirectoryExists(aFolder) then
        RemoveDir ( aFolder );  // Удалим саму папку
    end;  // of TDBTools.DeleteFolder

    (FindClose(Found) должен быть после условного блока, а не внутри его).
  • sniknik © (14.11.17 10:28) [19]
    > (FindClose(Found) должен быть после условного блока, а не внутри его).
    не должен, при не найденности/ошибке FindFirst не возвращает хендла, закрывать нечего.
  • IGray (14.11.17 11:35) [20]

    > А так?

    Большое спасибо, что вникли, изменение вроде логичное, но результат тот же.
  • IGray (14.11.17 11:37) [21]

    > sniknik ©   (14.11.17 10:28) [19]
    > > (FindClose(Found) должен быть после условного блока, а
    > не внутри его).
    > не должен, при не найденности/ошибке FindFirst не возвращает
    > хендла, закрывать нечего.

    ответил на предыдущий пост не заметив вашего.. спасибо!
  • rrrrrrrr (14.11.17 13:51) [22]
    сли б что-то блокировало, тоя ведь и фаром удалить бы не смог, так?

    давай давай, рассказывай про процедуры которым не все равно "конкретное место"
    ты такой оригинальный, и примерно миллионный здесь, который верит в эту хрень.
  • IGray (14.11.17 15:29) [23]

    > ты такой оригинальный, и примерно миллионный здесь, который
    > верит в эту хрень.


    а по делу есть что сказать? Или просто пофлудить охота, уникальный ты наш?

    Речь о фактах, а не о том, кто во что верит, а во что не верит..
    У нас свобода вероисповедания))
  • RemoveDir (14.11.17 16:00) [24]
    > а по делу есть что сказать?

    А по делу, создай проект с одним баттоном, который активизирует твою процедуру. И убедись что проблема далеко не в процедуре, а в твоей программе, действия которой ты не до конца обозреваешь и контролируешь :(
  • K-1000 © (14.11.17 16:19) [25]
    Может эту строчку убрать?:

    if DirectoryExists(aFolder) then

  • IGray (14.11.17 19:49) [26]
    > if DirectoryExists(aFolder) then
    не помогло


    > создай проект с одним баттоном, который активизирует твою
    > процедуру.
    Это было первое, что я сделал, но работоспособность в частном случае ведь не означает работоспособности всегда и везде. Особенно когда речь идёт о Windows )))

    > проблема далеко не в процедуре, а в твоей программе,
    > действия которой ты не до конца обозреваешь и контролируешь :(
    А это было первое, что я подумал, ибо непогрешимым себя не считаю, да и вообще, полный контроль - иллюзия ))

    Я считал, что блокировки нет, так как фаром и проводником (вместо процедуры) удалять папку удавалось, но только что я выяснил, что и фар и проводник МУХЛЕВАЛИ (!) Они только имитировали немедленное удаление, но после обновления папка появлялась вновь.
    К счастью я вспомнил, что есть такой классный зверь как ProcessExplorer и выяснил, что блокировка таки имеется. Не файлов в папке, а самой удаляемой папки. Хотя я лично ничем сам её не блокирую, но возможно что-то не освобождает одна из сторонних либ, придётся в них копаться..

    Всем спасибо за внимание к моему вопросу!
  • Игорь Шевченко © (14.11.17 21:19) [27]
    IGray   (14.11.17 19:49) [26]

    Procmon + просмотр стека на операциях с каталогом
  • rrrrrr © (14.11.17 22:14) [28]
    Я считал, что блокировки нет, так как фаром и проводником (вместо процедуры) удалять папку удавалось,

    ....

    что блокировка таки имеется.

    Не файлов в папке, а самой удаляемой папки.

    что и было сказано еще в [2]
 
Конференция "Начинающим" » Что не так с этой простой процедурой?
Есть новые Нет новых   [118449   +37][b:0][p:0.003]