Что нового

Копируем файлы без "тормозов"

Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Можно копировать одновременно до 256 файлов или папок. Для этого есть 256 слотов (от 0 до 255), см. четвертый параметр у функции _Copy_CopyDir(). По умолчанию используется первый слот (0). Для того, чтобы запустить несколько заданий одновременно, нужно чтобы ID у всех заданий были разные (0, 1, 2 и т.д.).

P.S

Функция должна возвращать ошибку 4 (Thread is now being used).
 

glax24

Знающий
Сообщения
72
Репутация
14
Помогите решить проблемы
1. Содержимое папки 1 скопировать в корень диска
Добавил переменную в функции Copy_Dir
$Pr_Path - 1 - копировать содержимое папки в корень, 0 - копировать саму папку

Код:
If $Pr_Path Then
$Path = $Destination
Else
$Path = $Destination & '\' & StringRegExpReplace($Source, '^.*\\', '')
EndIf                
If FileExists($Path) And $Pr_Path = 0 Then
If MsgBox(52, '', $Path & ' already exists.' & @CR & @CR & 'Do you want to replace it?', 0, $Form1) <> 6 Then
Return -1
;ContinueLoop
 EndIf


Можно ли как-то по другому?

2.Выдает ошибку Folder was not copied 5 если у заменяемого файла атрибут только на чтение.
Какой флаг надо поставить чтобы перезаписать все файлы?

3. При данной реализации при копирование процессор загружается на 100%.
Как исправить?
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include "Copy.au3"

Global $Copy = False,$Path,$State,$Data
If Not _Copy_OpenDll() Then
    MsgBox(16, '', 'DLL not found.')
    Exit
EndIf

$Source1 = @ScriptDir&'\na_flesh' ; Надо копировать содержие папки в корень(Копируется сама папка)
$Destination1 = 'G:\'
$Source2 = 'h:\A386'
$Destination2 = 'G:\'

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 295, 287, 345, 175)
$Button_Start = GUICtrlCreateButton("Старт", 72, 96, 121, 33)
$Progress = GUICtrlCreateProgress(0, 152, 289, 25)
$Label = GUICtrlCreateLabel("", 0, 192, 292, 28)
$Label1 = GUICtrlCreateLabel("", 0, 230, 292, 28)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1

    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button_Start
			Start()
EndSwitch
WEnd
Func Start()
	GUICtrlSetData($Label1, 'Func_1')
	Copy_Start($Source1,$Destination1,1)
	GUICtrlSetData($Label1, 'Func_2')
	Copy_Start($Source2,$Destination2,0)
	GUICtrlSetData($Label1, 'Func_End')
EndFunc ; ===>Start()

;$Pr_Path - 1 - копировать содержимое папки в корень, 0 - копировать саму папку
Func Copy_Start($Source, $Destination, $Pr_Path)

$res = Copy_Dir($Source,$Destination,$Pr_Path)
If $res < 0 Then Return -1

While 1
;-----copy----
    If $Copy Then
        $State = _Copy_GetState()
        If $State[0] Then
            If $State[0] = -1 Then
                ; Preparing
            Else
                $Data = Round($State[1] / $State[2] * 100)
                If GUICtrlRead($Progress) <> $Data Then
                    GUICtrlSetData($Progress, $Data)
                EndIf
                $Data = StringRegExpReplace($State[6], '^.*\\', '')
                If GUICtrlRead($Label) <> $Data Then
                    GUICtrlSetData($Label, $Data)
                EndIf
            EndIf
        Else
            Switch $State[5]
                Case 0
                    GUICtrlSetData($Progress, 100)
                    MsgBox(64, '', 'Folder was successfully copied.', 0, $Form1)
                Case 1235 ; ERROR_REQUEST_ABORTED
                    MsgBox(16, '', 'Folder copying was aborted.', 0, $Form1)
                Case Else
                    MsgBox(16, '', 'Folder was not copied.' & @CR & @CR & $State[5], 0, $Form1)
            EndSwitch
            GUICtrlSetState($Button_Start, $GUI_ENABLE)
            GUICtrlSetData($Progress, 0)
            GUICtrlSetData($Label, '')
            GUICtrlSetData($Button_Start, 'Старт')
            $Copy = 0
			ExitLoop
        EndIf
    EndIf
;----end copy-----
WEnd

EndFunc ;===>Copy_Start()

Func Copy_Dir($Source, $Destination,$Pr_Path)

	 If $Copy Then
                _Copy_Abort()
            Else
                If (Not $Source) Or (Not $Destination) Then
                    MsgBox(16, '', 'The source and destination folders must be specified.', 0, $Form1)
                    Return -1
					;ContinueLoop
                EndIf
                If $Pr_Path Then
				$Path = $Destination
			Else
				$Path = $Destination & '\' & StringRegExpReplace($Source, '^.*\\', '')
			EndIf
                If FileExists($Path) And $Pr_Path = 0 Then
                    If MsgBox(52, '', $Path & ' already exists.' & @CR & @CR & 'Do you want to replace it?', 0, $Form1) <> 6 Then
                        Return -1
						;ContinueLoop
                    EndIf
                EndIf
                GUICtrlSetState($Button_Start, $GUI_DISABLE)
                GUICtrlSetData($Button_Start, 'Отменить')
                _Copy_CopyDir($Source, $Path)
                $Copy = 1
            EndIf
Return 1
EndFunc ; ===>Copy_Dir()
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если честно, то я мало что понял из вопроса.

glax24 сказал(а):
Выдает ошибку Folder was not copied 5 если у заменяемого файла атрибут только на чтение.
Какой флаг надо поставить чтобы перезаписать все файлы?

Перед копированием нужно снять атрибут "Только чтение".

glax24 сказал(а):
При данной реализации при копирование процессор загружается на 100%.
Как исправить?

У меня сейчас стоит Windows 7, и загрузка ~10%, как и в проводнике Windows. В XP, вроде бы, была загрузка тоже под потолок. В любом случае, это системные функции, и как используется процессор зависит только от самой системы. Этот показатель должен быть приблизительно равен оному в проводнике.

P.S

Лучше копировать файлы последовательно, а не всем скопом, т.к. в последнем случае скорость будет заметно ниже.
 

glax24

Знающий
Сообщения
72
Репутация
14
При данной реализации при копирование процессор загружается на 100%.
Как исправить?
Здается мне что я где то напутал, а найти не могу где. Т.к в вашем примере такого эффекта нет.
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include "Copy.au3"

Global $Copy = False,$Path,$State,$Data
If Not _Copy_OpenDll() Then
    MsgBox(16, '', 'DLL not found.')
    Exit
EndIf

$Source1 = @ScriptDir&'\na_flesh' ; Надо копировать содержие папки в корень(Копируется сама папка)
$Destination1 = 'G:\'
$Source2 = 'h:\A386'
$Destination2 = 'G:\'

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 295, 287, 345, 175)
$Button_Start = GUICtrlCreateButton("Старт", 72, 96, 121, 33)
$Progress = GUICtrlCreateProgress(0, 152, 289, 25)
$Label = GUICtrlCreateLabel("", 0, 192, 292, 28)
$Label1 = GUICtrlCreateLabel("", 0, 230, 292, 28)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1

    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button_Start
            Start()
EndSwitch
WEnd
Func Start()
    GUICtrlSetData($Label1, 'Func_1')
    Copy_Start($Source1,$Destination1,1)
    GUICtrlSetData($Label1, 'Func_2')
    Copy_Start($Source2,$Destination2,0)
    GUICtrlSetData($Label1, 'Func_End')
EndFunc ; ===>Start()

;$Pr_Path - 1 - копировать содержимое папки в корень, 0 - копировать саму папку
Func Copy_Start($Source, $Destination, $Pr_Path)

$res = Copy_Dir($Source,$Destination,$Pr_Path)
If $res < 0 Then Return -1

While 1
;-----copy----
    If $Copy Then
        $State = _Copy_GetState()
        If $State[0] Then
            If $State[0] = -1 Then
                ; Preparing
            Else
                $Data = Round($State[1] / $State[2] * 100)
                If GUICtrlRead($Progress) <> $Data Then
                    GUICtrlSetData($Progress, $Data)
                EndIf
                $Data = StringRegExpReplace($State[6], '^.*\\', '')
                If GUICtrlRead($Label) <> $Data Then
                    GUICtrlSetData($Label, $Data)
                EndIf
            EndIf
        Else
            Switch $State[5]
                Case 0
                    GUICtrlSetData($Progress, 100)
                    MsgBox(64, '', 'Folder was successfully copied.', 0, $Form1)
                Case 1235 ; ERROR_REQUEST_ABORTED
                    MsgBox(16, '', 'Folder copying was aborted.', 0, $Form1)
                Case Else
                    MsgBox(16, '', 'Folder was not copied.' & @CR & @CR & $State[5], 0, $Form1)
            EndSwitch
            GUICtrlSetState($Button_Start, $GUI_ENABLE)
            GUICtrlSetData($Progress, 0)
            GUICtrlSetData($Label, '')
            GUICtrlSetData($Button_Start, 'Старт')
            $Copy = 0
            ExitLoop
        EndIf
    EndIf
;----end copy-----
WEnd

EndFunc ;===>Copy_Start()

Func Copy_Dir($Source, $Destination,$Pr_Path)

     If $Copy Then
                _Copy_Abort()
            Else
                If (Not $Source) Or (Not $Destination) Then
                    MsgBox(16, '', 'The source and destination folders must be specified.', 0, $Form1)
                    Return -1
                    ;ContinueLoop
                EndIf
                If $Pr_Path Then
                $Path = $Destination
            Else
                $Path = $Destination & '\' & StringRegExpReplace($Source, '^.*\\', '')
            EndIf
                If FileExists($Path) And $Pr_Path = 0 Then
                    If MsgBox(52, '', $Path & ' already exists.' & @CR & @CR & 'Do you want to replace it?', 0, $Form1) <> 6 Then
                        Return -1
                        ;ContinueLoop
                    EndIf
                EndIf
                GUICtrlSetState($Button_Start, $GUI_DISABLE)
                GUICtrlSetData($Button_Start, 'Отменить')
                _Copy_CopyDir($Source, $Path)
                $Copy = 1
            EndIf
Return 1
EndFunc ; ===>Copy_Dir()
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Поставьте в цикле Sleep(1).
 

glax24

Знающий
Сообщения
72
Репутация
14
Yashied
Попробуйте создайте каталог, а в нем файл с атрибутом только на чтение.
При повторном копирование будет ошибка.
5528817.png
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
glax24 [?]
а в нем файл с атрибутом только на чтение.
При повторном копирование будет ошибка.
Наверное, в этом случае надо собирать файлы из папки в 2-х мерный массив (имя - атрибуты), снимать у файлов атрибуты, копировать, а после копирования восстанавливать атрибуты (если надо).
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Атрибут "Только для чтения" как раз и предназначен для того, чтобы были проблемы при удалении файлов. Вам нужно просто рекурсивно снять атрибуты "Только для чтения" и "Скрытый" у файлов в заменяемой папке и всех ее подпапках. При копировании все атрибуты будут соответствовать исходным файлам.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied,
Чтобы снять определенные атрибуты у файлов и, если нужно, восстановить эти атрибуты после копирования (перемещения), нужно получить имена всех файлов в папке (подпапках). А имея список файлов, ИМХО, проще использовать _Copy_CopyFile().
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Ладно, не замарачивайтесь, вот новая Copy.dll. Она сама снимает "Read Only" и "Hidden" атрибуты при копировании и перемещении папок. При копировании и перемещении отдельных файлов, как и раньше, вы получите ошибку ERROR_ACCESS_DENIED (5).
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
Она сама снимает "Read Only" и "Hidden" атрибуты при копировании и перемещении папок.
Спасибо! :thanks:
Два вопроса:
1. Атрибуты только снимает или восстанавливает исходные?
2. Будет ли версия х64?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
Атрибуты только снимает или восстанавливает исходные?

Восстанавливать атрибуты не нужно, это делается автоматически самой системой. А вот чтобы перезаписать файл с этими атрибутами, их необходимо предварительно снять у старого файла, в противном случае система выдаст ошибку. Copy.dll снимает эти атрибуты только перед самой перезаписью, и, если, что-то не так, то у других файлов атрибуты остануться нетронутыми.

madmasles сказал(а):
Будет ли версия х64?

Конечно, как только доберусь до соответствующей системы.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied,
Понял, еще раз спасибо. :thanks:
 

glax24

Знающий
Сообщения
72
Репутация
14
Yashied спасибо за помощь.
Получилось что задумал, на вход функции можно подавать как каталоги так и файлы
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include "Copy.au3"

Global $Copy = False,$State,$Data
If Not _Copy_OpenDll() Then
    MsgBox(16, '', 'DLL not found.')
    Exit
EndIf

$Source1 = @ScriptDir&'\na_flesh'
$Destination1 = 'G:\'
$Source2 = 'h:\BCDW\ACRONIS.ISO'
$Destination2 = 'G:\ACRONIS.ISO'
$Source3 = 'h:\A386'
$Destination3 ='G:\A386'


#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 295, 287, 345, 175)
$Button_Start = GUICtrlCreateButton("Старт", 72, 96, 121, 33)
$Button_Stop = GUICtrlCreateButton("Стоп", 72, 96, 121, 33)
GUICtrlSetState($Button_Stop,$GUI_HIDE)
$Progress = GUICtrlCreateProgress(0, 152, 289, 25)
$Label = GUICtrlCreateLabel("", 0, 192, 292, 28)
$Label1 = GUICtrlCreateLabel("", 0, 230, 292, 28)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1

    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button_Start
			Start()
		EndSwitch
WEnd
Func Start()
	GUICtrlSetData($Label1, 'Func_1')
	Copy_Start($Source1,$Destination1)
	GUICtrlSetData($Label1, 'Func_2')
	Copy_Start($Source2,$Destination2)
	;Copy_Start($Source3,$Destination3)
	GUICtrlSetData($Label1, 'Func_End')
EndFunc ; ===>Start()

Func Copy_Start($Source, $Destination)

$res = Copy_File_Dir($Source,$Destination)
If $res < 0 Then Return -1

While 1
;-----copy----
    If $Copy Then
        $State = _Copy_GetState()
        If $State[0] Then
            If $State[0] = -1 Then
                ; Preparing
            Else
                $Data = Round($State[1] / $State[2] * 100)
                If GUICtrlRead($Progress) <> $Data Then
                    GUICtrlSetData($Progress, $Data)
                EndIf
                $Data = StringRegExpReplace($State[6], '^.*\\', '')
                If GUICtrlRead($Label) <> $Data Then
                    GUICtrlSetData($Label, $Data)
                EndIf
            EndIf
        Else
            Switch $State[5]
                Case 0
                    GUICtrlSetData($Progress, 100)
                    ;MsgBox(64, '', 'Данные успешно скопированы.', 0, $Form1)
					GUICtrlSetData($Label, 'Данные успешно скопированы.')
                Case 1235 ; ERROR_REQUEST_ABORTED
                    MsgBox(16, '', 'Копирование было прервано.', 0, $Form1)
                Case Else
                    MsgBox(16, '', 'Данные не были скопированы.' & @CR & @CR & $State[5], 0, $Form1)
            EndSwitch
            ;GUICtrlSetState($Button_Start, $GUI_ENABLE)
			GUICtrlSetState($Button_Start, $GUI_SHOW)
			GUICtrlSetState($Button_Stop, $GUI_HIDE)
            GUICtrlSetData($Progress, 0)
            GUICtrlSetData($Label, 'Данные успешно скопированы.')
            $Copy = 0
			ExitLoop
        EndIf
    EndIf
;Sleep(1)
;----end copy-----
$nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button_Stop
			 _Copy_Abort()
EndSwitch
WEnd

EndFunc ;===>Copy_Start()

Func Copy_File_Dir($Source, $Destination)

                If (Not $Source) Or (Not $Destination) Then
                    MsgBox(16, '', 'Источник и назначение не определены', 0, $Form1)
                    Return -1
					;ContinueLoop
                EndIf
				If FileExists($Destination) And StringLen($Destination) >3 Then
                   If MsgBox(36, '', $Destination & ' уже существует.' & @CR & @CR & 'Заменить?', 0, $Form1) <> 6 Then
                       Return -1
                       ;ContinueLoop
				   EndIf
				   GUICtrlSetData($Label, 'Удаление ' & $Destination)

						  If StringInStr(FileGetAttrib($Source), "D") = 0 Then

						     If StringInStr(FileGetAttrib($Destination),  "R") <> 0 Then FileSetAttrib($Destination,'-R+N')
						     FileDelete($Destination)
						Else
                                DirRemove($Destination,1)
                          EndIf
               EndIf
                ;GUICtrlSetState($Button_Start, $GUI_DISABLE)
				GUICtrlSetState($Button_Start, $GUI_HIDE)
				GUICtrlSetState($Button_Stop, $GUI_SHOW)
				If StringInStr(FileGetAttrib($Source), "D") = 0 Then
				_Copy_CopyFile($Source, $Destination)
				Else
                _Copy_CopyDir($Source, $Destination)
				EndIf
                $Copy = 1

Return 1
EndFunc ; ===>Copy_Dir()
 

glax24

Знающий
Сообщения
72
Репутация
14
Yashied
Как решить проблему. При копирование каталога с жесткого например на флешку, а в каталоге файл autorun.inf и при включенном антивируснике ясное дело копирование этого файла блокируется, и соответственно из за одного файла прекращается копирование всего каталога (копирование завершается с ошибкой).
 

glax24

Знающий
Сообщения
72
Репутация
14
Код:
$listdir = _FileListToArray($PATH_DIR1, '*', 0) ; список файлов и/или папок
		For $i = 1 To $listdir[0]
		If $listdir[$i] = 'autorun.inf' Then ContinueLoop
		Copy_Start($PATH_DIR1 & $listdir[$i], $PATH_DIR2 & $listdir[$i])
        Next

Нашел решение, только так.
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Обновил библиотеку, исправлена одна ошибка.
 

Pavel

Новичок
Сообщения
125
Репутация
3
Подскажите, с каким флагом нужно использовать функцию _Copy_FileCopy, чтобы автоматически создавать папки по пути назначения? (аналог флага '8' у стандартной FileCopy)
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Для копирования папок нужно использовать _Copy_CopyDir(), см. Copy_Ex2.au3 в архиве.
 

Pavel

Новичок
Сообщения
125
Репутация
3
Yashied, мне нужно не папку копировать, а списки файлов, сохраняя структуру папок. FileCopy с флагом '8' это умеет, но зачастую подвисает на больших файлах + подвисает при выполнении.
 
Верх