Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Вопрос по SHFileOperation и удаление


Автор: den1977 23.8.2010, 12:13
Из папки 'C:\Test\' нужно удалить все файлы подкаталоги (оставив саму папку 'C:\Test\' )

Делаю так: 
Код

uses ShellApi

procedure TForm1.Button1Click(Sender: TObject);
var sh : SHFILEOPSTRUCT;
begin
sh.Wnd := Application.Handle;
sh.wFunc := FO_DELETE;
sh.pFrom := 'C:\Test\*.*';
sh.pTo := nil;
sh.fFlags := FOF_NOCONFIRMATION + FOF_SILENT;
sh.fAnyOperationsAborted := False;
sh.hNameMappings := nil;
sh.lpszProgressTitle := nil;
SHFileOperation(sh);
end;


В целом работает (удаляет из указанной папки все как надо), но если вдруг попадается занятый файл, то выдается сообщение и удаление прекращается.

http://ipicture.ru/Gallery/Viewfull/938426.html

Как сделать чтобы вместо вывода сообщения - стало - пропустить занятые файлы и продолжить удаление остальных файлов и папок?? 

Если можно, то пожайлуста внесите нужные изменения в код или дайте примерчик как это сделать!

Автор: kami 23.8.2010, 12:25
Код

sh.fFlags := FOF_NOCONFIRMATION + FOF_SILENT+ FOF_NOERRORUI;

Автор: Alexeis 23.8.2010, 12:26
Цитата(den1977 @  23.8.2010,  11:13 Найти цитируемый пост)
пропустить занятые файлы

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

Добавлено через 1 минуту и 13 секунд
kami, что-то мне подсказывает, что FOF_NOERRORUI просто не выкинет сообщение об ошибке, но реально произведет отмену всей операции.

Автор: den1977 23.8.2010, 13:43
Да действительно если написать:

Код

sh.fFlags := FOF_NOCONFIRMATION + FOF_SILENT+ FOF_NOERRORUI;


Получается отключение показа сообщение об ошибке, но дальнейшее удаление все равно отменяется!!!  smile 

Но как пропустить занятые файлы (и/или папки)  smile  и продолжить удаление остальных файлов и папок??  smile 


Автор: Alexeis 23.8.2010, 13:54
Цитата(den1977 @  23.8.2010,  12:43 Найти цитируемый пост)
Но как пропустить занятые файлы (и/или папки) 


Я бы сделал используя код аналогичный этому http://forum.vingrad.ru/topic-82343.html

Автор: den1977 23.8.2010, 14:10
Цитата(Alexeis @  23.8.2010,  13:54 Найти цитируемый пост)
Я бы сделал используя код аналогичный этому http://forum.vingrad.ru/topic-82343.html


Я конечно извеняюсь, но чем мне поможет "рекурсивный обход дерева каталогов" в данной ситуации, ведь если начать удалять все согластно полученного списка, то все-равно когда SHFILEOPSTRUCT наткнется на занятый файл получится то-же самое  smile  , ведь и без списка когда нет занятых файлов SHFILEOPSTRUCT прекрастно все удаляет  smile  

Автор: Alexeis 23.8.2010, 14:13
Цитата(den1977 @  23.8.2010,  13:10 Найти цитируемый пост)
ведь если начать удалять все согластно полученного списка, то все-равно когда SHFILEOPSTRUCT наткнется на занятый файл получится то-же самое

  А зачем тут SHFILEOPSTRUCT ? Файл/пустую диреторию можно удалить при помощи DeleteFile() . Результат можно совсем не проверять, все что не сможет так и останется.

Автор: den1977 23.8.2010, 15:50
Попробовал последовать совету Alexeis Вроде все работает как мне надо, но навсякий случай попробовал выводить перед удалением результаты поиска в memo1 и увидел что имена там отбражаются довольно странно  smile  (скорее всего я тут где-то, что-то напутал  smile )
Может кто проверит и исправит то, что не так smile  А то я чего-то запутался smile  Да и получить в дальнейшем глюки опасаюсь  
Код

procedure DelAllFind(path: string);
    var sr:Tsearchrec;// Описываем структуру, которую использует для поиска система
  found,i:integer; // найдено или нет
begin
  found:=FindFirst(path + '*.*', FaAnyfile, sr);
  while (found = 0) do // если хоть что-то найдено
   begin
    if (sr.name <> '.') and (sr.name <> '..') then
    begin // если это не указатели на корневые каталоги, то чтото нашли
        DelAllFind(path+sr.name);
        form1.memo1.lines.append(path+sr.name);
        DeleteFile(path+sr.name);
      if (sr.attr and FaDirectory) = FaDirectory then
// ага вот поддиректория - вызываем себя рекурсивно, но с поиском уже в этой директории
        begin
          DelAllFind(path+sr.name+'\');
          form1.memo1.lines.append(path+sr.name+'\');
          DeleteFile(path+sr.name);
          RemoveDir(path+sr.name+'\');
        end;
      end;
   found:=findnext(sr); // есть ли еще файлы или каталоги
   end;
   FindClose(sr); // поиск закончен - нужно освободить память
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
DelAllFind('c:\test\');
end;


И ксати может кто все-таки поможет с изначальным вопросм по SHFILEOPSTRUCT  smile 

Автор: Alexeis 23.8.2010, 19:18
  А зачем делать DelAllFind(path+sr.name); для файлов? файл же не папка чтобы его перечислять.

Кроме того
DeleteFile(path+sr.name);
RemoveDir(path+sr.name+'\');

это что за "двойной удар"?

Автор: den1977 23.8.2010, 21:36
Учел замечания Alexeis - мда перестарался я чуток   smile 
Вроде так правильнее, пожалуйста проверьте и исправьте если, что не так  smile 

Подскажите пожалуйста - заметил, что если файл или папка имеют атрибут "только чтение", то они остаются, что и куда нужно добавить в этот код для удаления файлов или папок независимо от атрибутов?   smile 

Код

procedure DelAllFind(path: string);
    var sr:Tsearchrec;// Описываем структуру, которую использует для поиска система
  found,i:integer; // найдено или нет
begin
  found:=FindFirst(path + '*.*', FaAnyfile, sr);
  while (found = 0) do // если хоть что-то найдено
   begin
    if (sr.name <> '.') and (sr.name <> '..') then
    begin // если это не указатели на корневые каталоги, то чтото нашли
          Form1.Memo1.lines.append(path+sr.name);
          DeleteFile(path+sr.name);
      if (sr.attr and FaDirectory) = FaDirectory then
// ага вот поддиректория - вызываем себя рекурсивно, но с поиском уже в этой директории
        begin
          DelAllFind(path+sr.name+'\');
          Form1.memo1.lines.append(path+sr.name+'\');
          RemoveDir(path+sr.name+'\');
        end;
      end;
   found:=findnext(sr); // есть ли еще файлы или каталоги
   end;
   FindClose(sr); // поиск закончен - нужно освободить память
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
DelAllFind('c:\test\');
end;


PS.:
Может кто все-таки поможет с изначальным вопросм по SHFILEOPSTRUCT  smile 

Автор: Alexeis 23.8.2010, 21:43
Цитата(den1977 @  23.8.2010,  20:36 Найти цитируемый пост)
заметил, что если файл или папка имеют атрибут "только чтение"

  Да, есть такое дело, можно перед удалением вызвать SetFileAttributes(path+sr.name, FILE_ATTRIBUTE_NORMAL)

Автор: den1977 23.8.2010, 21:54
Цитата(Alexeis @  23.8.2010,  22:43 Найти цитируемый пост)
Да, есть такое дело, можно перед удалением вызвать SetFileAttributes(path+sr.name, FILE_ATTRIBUTE_NORMAL) 


При попытке это использовать получил такую ошибку 
[Pascal Error] Unit1.pas(75): E2010 Incompatible types: 'string' and 'PAnsiChar'

А так прошло - SetFileAttributes(PAnsiChar(path+sr.name), FILE_ATTRIBUTE_NORMAL); - так правильно?

Автор: Alexeis 23.8.2010, 21:58
Цитата(den1977 @  23.8.2010,  20:54 Найти цитируемый пост)
А так прошло

Ну да, все верно, это я ступил. В MSDN также отмечено про read only файлы.

Автор: den1977 23.8.2010, 22:04
Alexeis и Всем большое спасибо за помощь и участие!!!  smile 
Все что хотел получилось !!!  smile 

PS.:
Но может кто все-таки поможет с изначальным вопросм по SHFILEOPSTRUCT  smile 
Теперь уже просто интерестно  smile 


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)