1

Тема: AHK: Копирование файлов из одной папки в другую и обратно

Здравствуйте. Бьюсь и всё не могу толкового ничего придумать:

copyto:
RowNumber = 0
Loop
{
RowNumber := LV_GetNext(RowNumber)
	if not RowNumber
		break
LV_GetText(folder, RowNumber, 2)
LV_GetText(filename, RowNumber, 1)
filecopy, %folder%\%filename%, %tofolder%, 1
}
return

Эта функция берёт из listview сведения (путь и имя) файлов выделенных пользователем и копирует в заранее указанную папку. Обычно, это от одного до десятка файлов. Таким образом совершаем нечто вроде резервного копирования. Как лучше организовать возможность конкретно эти же файлы потом из "tofolder" в "folder" копировать, вне зависимости от выделенных на данный момент строк?

Пример:
1) Выделяем в listview три файла, жмём горячую клавишу - функция выполняется, мы скопировали три файла в папку назначения.
2) Выделяем два других файла, жмём горячую клавишу - докопировались ещё два файла.
3) Выделяем какие-нибудь другие файлы, сворачиваем программу, открываем сторонний процесс или просто бездействуем.
4) Жмём другую горячую клавишу - два последних скопированных файла скопировались обратно из папки назначения в папку-источник.

Есть же какое-то простое решение и я вроде бы его даже знал, но оно никак не смогло вновь нарисоваться в воображении. Пробовал запоминать в массиве (не самый привлекательный метод) и через ввод дополнительных переменных, но не удалось.
Помогите, пожалуйста.

2

Re: AHK: Копирование файлов из одной папки в другую и обратно

Oomniq пишет:

Таким образом совершаем нечто вроде резервного копирования. Как лучше организовать возможность конкретно эти же файлы потом из "tofolder" в "folder" копировать, вне зависимости от выделенных на данный момент строк?

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

3 (изменено: Oomniq, 2017-04-19 22:01:08)

Re: AHK: Копирование файлов из одной папки в другую и обратно

Пробовал запоминать в массиве (не самый привлекательный метод) и через ввод дополнительных переменных, но не удалось.


copyto:
i = 0
RowNumber = 0
Loop
{
RowNumber := LV_GetNext(RowNumber)
	if not RowNumber
		break
i:=i+1
LV_GetText(folder, RowNumber, 2)
LV_GetText(filename, RowNumber, 1)
filecopy, %folder%\%filename%, %tofolder%, 1
m%i%:=filename
}
return

copyout:
loop
{
if i<1
break
filecopy, %tofolder%\m%i%, %folder%, 1 				;	?
i:=i-1
}
return

Такой вариант, разумеется, не прокатил. Были и другие, но всё равно не справился. Какой тут правильный синтаксис? Или всё-таки реализуется иначе?

4

Re: AHK: Копирование файлов из одной папки в другую и обратно

Посмотрите в англоязычной справке про массивы. Проще всего начать с псевдомассивов (Pseudo-Arrays):

Array%j% := A_LoopField

То есть сохраняете содержимое ячеек в переменные с похожими названиями, плюс ещё одна переменная, хранящая их количество.

5

Re: AHK: Копирование файлов из одной папки в другую и обратно

Справился, спасибо:

copyout:
loop
{
if i<1
break
g:=m%i%
filecopy, %tofolder%\%g%, %folder%, 1
i:=i-1
}
return

6

Re: AHK: Копирование файлов из одной папки в другую и обратно

Такой небольшой пример может оказаться интересным, для использования массивов с ListView:


#SingleInstance, Force
#NoEnv
SetWorkingDir, A_ScriptDir
SetBatchLines, -1

; >>--++--<<  >>--++--<< 
	tableNames:=["Содержимое"]
; >>--++--<<  >>--++--<< 

Gui, 1:Add,ListView,w760 h300 NoSort vLVval +LV0x00010000 +HwndLV_H
Gui, 1:Add,Button,xm y+10 gGetFiles,Получить файлы из папки
Gui, 1:Show,,Список
Menu,MyContextMenu,Add,Получить выбранные строки,GetRows	; Заполняет массив selectedRowsArr выделенными строками
Menu,MyContextMenu,Add,Получить выбранную строку,GetItem	; Возвращает значение из исходного массива, расположение которого
															; получается по клику в координатах вызова контекстного меню 
return

; >>--++--<< SUB >>--++--<< 

GuiClose:
	ExitApp
GetFiles:
	InputBox,myPath,Выбор,Указать полный путь к папке.,,,,,,,,%A_MyDocuments%
	if (ErrorLevel==1)
		return
	filesArr:=[]							; очистить переменную
	mask:=% RTrim(myPath,"\") "\*.*"
	Loop,%mask%,,1
	{
		tmpArr:=[]
		tmpArr:=[A_LoopFileFullPath]
		filesArr.Push(tmpArr)
	}
	tmpTable:=[],tmpTable.Push(tableNames,filesArr*)
	ReCreateTable(tmpTable)
return
GetRows:
	loopStartAt:=0
	selectedRowsArr:=[]						; массив выделенных строк
	if (newRowNmbr-selectedRows>0)
		loopStartAt:=newRowNmbr-selectedRows
	Loop {
		loopStartAt:=LV_GetNext(loopStartAt)
		if (!loopStartAt)
			break
		LV_GetText(Text,loopStartAt)
		selectedRowsArr.Push(Text)
	}
	MsgBox,,Результат,% Format("Выделено строк -> {1}.`nПервая содержит путь:`n{2}.`n`nПоследняя содержит путь:`n{3}",i:=selectedRowsArr.Length(),selectedRowsArr[1],selectedRowsArr[i])
return
GetItem:
	MsgBox,,Результат,% LV_Item
return
GuiContextMenu:
	if (A_GuiControl!="LVval")
		return
	newRowNmbr:=A_EventInfo										; Номер строки в которую был совершён клик
	selectedRows:=LV_GetCount("S")
	if (newRowNmbr>0) {
		LV_Item:=tmpTable[newRowNmbr+1][LV_GetColNmbr(LV_H)]	; Получать элементы можно так же из массива, а не только из таблицы.
																; Поскольку первый элемент это имена для столбцов, основное
																; содержимое начинается со второго элемента, поэтому номер строки
																; указывается как newRowNmbr+1
		Menu, MyContextMenu, Show, %A_GuiX%, %A_GuiY%
	}
return
; >>--++--<< FUNC >>--++--<< 

; #========================================================================================#
;	ReCreateTable(tableArr) - Перезаполняет ListView новыми данными.
;								 Принимает массив массивов, где первым его элементом должен
;								 быть массив, содержащий имена для столбцов. Количество
;								 элементов в содержащихся массивах должно быть одинаковым.
; #========================================================================================#
ReCreateTable(tableArr) {					; пересоздаёт ListView из полученного массива
	Global
	GuiControl, -ReDraw, LVval
	LV_Delete()								; удалить содержимое ListView
	Loop, % LV_GetCount("Column")
		LV_DeleteCol(1)
	Loop,% tableArr[1].Length()			; задать имена колонкам, содержащиеся в первом массиве
		LV_InsertCol(A_Index,"", tableArr[1][A_Index])
	Loop,% tableArr.Length()-1 {			; распихать содержимое остальных массивов по колонкам в новой строке для каждого
		rNmbr := LV_Add("", "")
		Loop,% tableArr[rNmbr+1].Length()
			LV_Modify(rNmbr, "Col" . A_Index, tableArr[rNmbr+1][A_Index])
	}
	Loop, % tableArr[1].Length()
		LV_ModifyCol(A_Index, "AutoHdr")
	GuiControl, +ReDraw, LVval
}
LV_GetColNmbr(HLV) {						; возвращает номер колонки, в которую был совершён клик
	Static LVM_SUBITEMHITTEST := 0x1039
	VarSetCapacity(POINT, 8, 0)
	DllCall("User32.dll\GetCursorPos", "Ptr", &POINT)
	DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &POINT)
	VarSetCapacity(LVHITTESTINFO, 24, 0)
	NumPut(NumGet(POINT, 0, "Int"), LVHITTESTINFO, 0, "Int")
	NumPut(NumGet(POINT, 4, "Int"), LVHITTESTINFO, 4, "Int")
	SendMessage, LVM_SUBITEMHITTEST, 0, &LVHITTESTINFO, , ahk_id %HLV%
	If (ErrorLevel = -1)
		Return 0
	Subitem := NumGet(LVHITTESTINFO, 16, "Int") + 1
		Return Subitem
}

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