purebasic.info

PureBasic forum
Текущее время: Вт ноя 13, 2018 7:53 am

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 11 ] 
Автор Сообщение
 Заголовок сообщения: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Сб сен 15, 2018 9:03 am 
Не в сети
профессор

Зарегистрирован: Вс авг 31, 2014 12:11 am
Сообщений: 448
Благодарил (а): 50 раз.
Поблагодарили: 20 раз.
Пункты репутации: 10
Здравствуйте.
Давно интересовал следующий вопрос: корректно ли будет форсированное прерывание процесса копирования/удаления на полпути?
В программе копирую/удаляю не отдельными файлами, а целыми директориями, предварительно занесёнными в список. Сейчас для безопасного прерывания процесса при очередном проходе цикла ForEach проверяется состояние глобальной переменной, чтобы ещё до начала процесса копирования/удаления очередной папки преждевременно выйти из цикла (Break). Но... файлов в каждой папке очень много и велика вероятность попасть в начало-середину процесса. Соответственно пройдёт ещё довольно много времени до остановки процесса (очередного прохода/итерации цикла и дальнейшей проверки состояния переменной). Получается "подвешенное" состояние программы, что не очень красиво.

В программе процесс копирования/удаления производится в доп. потоке. На окно установлен Callback. В процедуре WindowCallback отлавливается сообщение #WM_COPYDATA (дело в том, что сигнал останова формируется в др. приложении). Так вот... если теперь в процедуре WindowCallback при получении кодового слова "в наглую" закрывать окно программы, то корректно ли это будет? Что ещё перед закрытием окна в таком случае указать, KillThread? Сейчас не волнует вопрос, что данные не допишутся. Это само собой разумеется.
Или зря заморочился с переменной, а корректное завершение процесса "ляжет" на ОС и можно смело прерывать?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Сб сен 15, 2018 6:32 pm 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 271
Благодарил (а): 14 раз.
Поблагодарили: 32 раз.
Пункты репутации: 0
Что-то я не нахожу api которая бы могла шлепнуть директорию. Похоже DeleteDirectory() это:DeleteFile_ + RemoveDirectory_.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Сб сен 15, 2018 7:45 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6397
Благодарил (а): 20 раз.
Поблагодарили: 200 раз.
Пункты репутации: 52
repeat писал(а):
Что-то я не нахожу api которая бы могла шлепнуть директорию. Похоже DeleteDirectory() это:DeleteFile_ + RemoveDirectory_.

Шлепнуть можно только пустую папку. Или предварительно очистить.
Из API есть SHFileOperation, может понравится:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
;======================================================================
;   ShareCopy.PB -  A Muli-Function Copy Tool that uses: Shell32.dll
;                   I found a subroutine on VB web-site -  author unknown
;                   modified for PureBasic -  Public Domain
;                   Bob Houle - updated Nov 02/02    blueb@shaw.ca
;  Адаптировал к PB v 5.60 и перевел kvitaliy
;======================================================================
#Window1 = 1
#W1Btn1 = 1
#W1Btn2 = 2
#W1Btn3 = 3
#W1Btn4 = 4
#W1Btn5 = 5
#W1String1 = 6
#W1String2 = 7
#W1Check1 = 8
#W1Check2 = 9
#W1Check3 = 10
#W1Check4 = 11
#W1Check5 = 12
#W1Text1 = 13
#W1Text2 = 14
 
#Window1Flags = #PB_Window_MinimizeGadget | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered
#Text1Flags = #PB_Text_Right
#Text2Flags = #PB_Text_Right
 
;======================================================================
;                [ Declares ]
;======================================================================
Declare MyWindowCallback(WindowID, Message, wParam, lParam)
Declare Button_Click(Index.l)
 
;======================================================================
;                [ Globals ]
;======================================================================
Global SHFileOp.SHFILEOPSTRUCT    ;Windows API Structure
 
;========================================================================================
 
WinW=800
WinH=230 ; Window sizes.
 
hWnd.l = OpenWindow(#Window1,0,0,WinW,WinH,"Window File Operations",#Window1Flags)
    ButtonGadget(#W1Btn1,7,200 ,89,25,"Copy")
   ButtonGadget(#W1Btn2,105,200 ,89,25,"Move")
   ButtonGadget(#W1Btn3,205,200 ,89,25,"Rename")
   ButtonGadget(#W1Btn4,305,200 ,89,25,"Delete")
   ButtonGadget(#W1Btn5,405,200 ,89,25,"Quit", 1)
   StringGadget(#W1String1,220,8,250,21,"")
   StringGadget(#W1String2,220,30 ,250,21,"")
   CheckBoxGadget(#W1Check1,90,80 ,491,17,"Не отображать диалоговое окно и процесс выполнения")
   CheckBoxGadget(#W1Check2,90,100 ,603,17,"Отвечать «Для всех» для любого отображаемого диалогового окна")
   CheckBoxGadget(#W1Check3,90,120 ,604,17,"Переименовывать файл (например: 'Copy #1 of...'), если имя уже существует")
   CheckBoxGadget(#W1Check4,90,140 ,584,17,"Не спрашивать подтверждения нового каталога, если это требует операция.")
   CheckBoxGadget(#W1Check5,90,160 ,598,17,"Выполнять операцию только с файлами, если указано имя файла подстановочного знака (*. *)")
   TextGadget(#W1Text1,50,12 ,161,17,"Исходный файл или папка", #Text1Flags)
   TextGadget(#W1Text2,50,35,161,17,"Файл назначения или папка", #Text2Flags)
 
 
If hWnd
;Message Loop
 
; ----- Windows Messages
  ; Callback is not required for this App, but included anyways :)
  ; Might want to reply to Windows messages.
  ; For now simply try re-sizing the window
 ; SetWindowCallback(@MyWindowCallback())
 
; ----- PB specific messages
 Repeat
   EventID.l = WaitWindowEvent()
 
  Select EventID
 
          Case #PB_Event_Gadget
 
              Select EventGadget()
               Case #W1Btn1 ;----------Copy
                    Button_Click(0)
               Case #W1Btn2 ;----------Move
                    Button_Click(1)
               Case #W1Btn3 ;----------Rename
                    Button_Click(2)
               Case #W1Btn4 ;----------Delete
                    Button_Click(3)
               Case #W1Btn5 ;----------Quit
                      EventID = #PB_Event_CloseWindow
              EndSelect
 
  EndSelect
 
 Until EventID = #PB_Event_CloseWindow
 
EndIf
 
End ; program finish
 
; *********************************************************************
;                [ Required Procedures ]
; *********************************************************************
 
 
;======================================================================
;                [ Callback Procedure ]
;======================================================================
Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
  Result = #PB_ProcessPureBasicEvents
    Select message
          Case #WM_SIZE    ;just testing
              Beep_(50,50)
    EndSelect
  ProcedureReturn Result
EndProcedure
 
;======================================================================
;                [ SHFileOperation API Procedure ]
;======================================================================
Procedure Button_Click(Index.l)
 
;define variables
 lFileOp.f
 lresult.l
 lFlags.w
 
;Get status of checkboxes
ChkDir.l = GetGadgetState(#W1Check4)
ChkFilesOnly.l = GetGadgetState(#W1Check5)
ChkRename.l = GetGadgetState(#W1Check3)
ChkSilent.l = GetGadgetState(#W1Check1)
ChkYesToAll.l = GetGadgetState(#W1Check2)
 
;Get the edit box values
FromDirectory.s = GetGadgetText(#W1String1)
ToDirectory.s = GetGadgetText(#W1String2)
 
;Find out which button was pressed
 Select Index
    Case 0
        lFileOp = #FO_COPY
    Case 1
        lFileOp = #FO_MOVE
    Case 2
        lFileOp = #FO_RENAME
    Case 3
         ChkYesToAll = 0      ;No mattter what - confirm Deletes! Prevents OOPS!
         lFileOp = #FO_DELETE
 EndSelect
 
If ChkSilent:lFlags = lFlags | #FOF_SILENT: EndIf
If ChkYesToAll: lFlags = lFlags | #FOF_NOCONFIRMATION:EndIf
If ChkRename: lFlags = lFlags | #FOF_RENAMEONCOLLISION: EndIf
If ChkDir: lFlags = lFlags | #FOF_NOCONFIRMMKDIR: EndIf
If ChkFilesOnly: lFlags = lFlags | #FOF_FILESONLY: EndIf
 
; NOTE:  If you add the #FOF_ALLOWUNDO Flag you can move
;        a file to the Recycle Bin instead of deleting it.
 
  SHFileOp\wFunc = lFileOp
  SHFileOp\pFrom = @FromDirectory
  SHFileOp\pTo = @ToDirectory
  SHFileOp\fFlags = lFlags
 
 lresult = SHFileOperation_(SHFileOp)
 
;  If User hit Cancel button While operation is in progress,
;  the fAnyOperationsAborted parameter will be true
;  - see win32api.inc For Structure details.
 
If lresult <> 0 | SHFileOp\fAnyOperationsAborted:EndIf: ProcedureReturn 0
 
 MessageRequester("Operation Has Completed", "PureBasic Rules!", 0)
  ProcedureReturn lresult
EndProcedure
; ================================================================


_________________
read-only ¯\_(ツ)_/¯


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Сб сен 15, 2018 8:27 pm 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 271
Благодарил (а): 14 раз.
Поблагодарили: 32 раз.
Пункты репутации: 0
kvitaliy писал(а):
Шлепнуть можно только пустую папку.
Про это и говорю, knower использует DeleteDirectory() из-за чего ждет пока все дескрипторы закроются, а если делать проверку после DeleteFile то можно обойтись без KillThread. SHFileOperation_ видел :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Вс сен 16, 2018 12:46 pm 
Не в сети
профессор

Зарегистрирован: Вс авг 31, 2014 12:11 am
Сообщений: 448
Благодарил (а): 50 раз.
Поблагодарили: 20 раз.
Пункты репутации: 10
repeat правильно истолковал вопрос. Подразумевалось, что если взять, к примеру только один каталог, "набитый" тысячами мелких файлов и запустить длительный процесс CopyDirectory() или DeleteDirectory(). И где-нибудь "посреди дороги" принудительно закрыть программу. Так делать можно или нельзя? Или нежелательно? К сожалению так и не услышал внятного ответа. Понял, что DeleteDirectory() содержит в себе: перебор всех файлов указанной папки -> удаление каждого файла (отдельно) -> удаление пустых директорий (постобработка). Кстати RemoveDirectory_ это и есть аналог консольной RD? У неё тоже есть такая замечательная особенность, которую активно использую. Удаляет только пустые каталоги.

kvitaliy, спасибо за публикацию. Пригодится.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Вс сен 16, 2018 2:05 pm 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 271
Благодарил (а): 14 раз.
Поблагодарили: 32 раз.
Пункты репутации: 0
knower, понаблюдайте в диспетчере задач за памятью:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Procedure test(*t)
  Static i
  Debug i
  i+1
  Repeat
    Delay(1)
  ForEver
EndProcedure
 
 
Thread = CreateThread(@test(), 0)
Repeat
  Delay(1)
  If x = 100
    KillThread(Thread)
    Thread = CreateThread(@test(), 0)
    x = 0
  EndIf
  x+1
ForEver

Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Global flag.b = 0
 
Procedure test(*t)
  Static i
  Debug i
  i+1
  Repeat
    If flag = 1
      flag = 0
      ProcedureReturn
    EndIf
    Delay(1)
  ForEver
EndProcedure
 
 
Thread = CreateThread(@test(), 0)
Repeat
  Delay(1)
  If x = 100
    flag = 1
    Repeat
      Delay(1)
    Until flag = 0
    Thread = CreateThread(@test(), 0)
    x = 0
  EndIf
  x+1
ForEver



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Вс сен 16, 2018 2:59 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6397
Благодарил (а): 20 раз.
Поблагодарили: 200 раз.
Пункты репутации: 52
knower писал(а):
И где-нибудь "посреди дороги" принудительно закрыть программу.

У SHFileOperation, в диалогах, есть механизм отмены операции при прерывании. Там всё корректно.

_________________
read-only ¯\_(ツ)_/¯


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Вс сен 16, 2018 4:33 pm 
Не в сети
профессор

Зарегистрирован: Вс авг 31, 2014 12:11 am
Сообщений: 448
Благодарил (а): 50 раз.
Поблагодарили: 20 раз.
Пункты репутации: 10
kvitaliy, да. Ещё раз спасибо за информацию. Встречал подобные примеры. НО... у меня там такая витиеватая структура/иерархия папок для обработки получается... что в данном случае системный диалог никак не подходит. Иначе он будет столько раз появляться/мелькать сколько каталогов нужно обработать. Несерьезно это, извините.
Один каталог взял только для примера, чтобы как говорится рассмотреть проблему в масштабе. Тем более всё уже готово и проценты выводятся и прогрессбар и кол-во байт соответственно скопировано/удалено. И в ListIconGadget'е можно наблюдать за ходом процесса. Вобщем... получается теперь так, что сделано всё, кроме самого главного.

repeat
понаблюдал. Первый код постоянно отъедает память. Согласен, что второй более правильный. Только извините, но куда девается эта память? Не понял юмора.
Однако замечено, что при завершении работы первого кода память всё-таки возвращается системе. Надо так понимать, что сама среда "подчищает"?

Эх... не хотелось переходить от папок к файлам... да видимо прийдётся. Иначе это не дело.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Вс сен 16, 2018 5:18 pm 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 271
Благодарил (а): 14 раз.
Поблагодарили: 32 раз.
Пункты репутации: 0
knower писал(а):
куда девается эта память?
В справке написано:
KillThread
Цитата:
Проблема в том, что поток немедленно уничтожается и не имеет возможности выполнить какой-либо код очистки (например, освобождение памяти, освобождение элементов, де-распределение собственного стека).

knower писал(а):
Надо так понимать, что сама среда "подчищает"?
Мои познания довольно скромны в этом вопросе, но, сомневаюсь что OC чистит память после таких киляний. Скорее всего обнуляется при выделении.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Пн сен 17, 2018 3:54 pm 
Не в сети
профессор

Зарегистрирован: Чт сен 22, 2011 6:21 pm
Сообщений: 263
Благодарил (а): 36 раз.
Поблагодарили: 25 раз.
Пункты репутации: 0
repeat писал(а):
...Скорее всего обнуляется при выделении.

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


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: CopyDirectory() и DeleteDirectory()
СообщениеДобавлено: Пн сен 17, 2018 4:22 pm 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 271
Благодарил (а): 14 раз.
Поблагодарили: 32 раз.
Пункты репутации: 0
Kuzmat писал(а):
Освобождается при завершении порождающего поток процесса
Я про данные говорю. То что адрес становится доступным это понятно.


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB