Page 1 of 1

Comparing folders?

Posted: 29 Dec 2018, 11:25
by vsub
I made a script that scan two folder and displays if there is any difference between the files.
The problem is,I am scanning the "source" folder but if there are new files in the second folder,ahk will not tell me

Here is a simple example
Folder 1:

file1
folder1\file1
folder1\file2

Folder2:
file1
folder1\file2

This will tell me that folder1\file1 is missing if I use Loop (files & folders)

Or
Folder 1:

file1
folder1\file1
folder1\file2

Folder2:
folder1\file1
folder1\file2
folder1\file3

Using Loop (files & folders) by setting the first example as source,will not tell me that there is folder1\file3 in the second folder

Code: Select all

Gui, Add, Edit, x3 y4 w720 h20 ReadOnly, 
Gui, Add, Edit, x3 y34 w720 h20 ReadOnly, 
Gui, Add, Button, x727 y4 w90 h20 , Source
Gui, Add, Button, x727 y34 w90 h20 , Destination
Gui, Add, Button, x364 y64 w90 h20 , Compare
Gui, Add, ListView, x3 y89 w812 h410 Grid,Files|Error
LV_ModifyCol(1,720)
LV_ModifyCol(2,60)
Gui, Add, Progress, x3 y502 w812 h20 cGreen Border vPG,0
Gui, Show, Center h530 w820,Compare Folders
Return


ButtonSource:
FileSelectFolder,Source,,0,Choose Source
If Source =
Return
GuiControl,,Edit1,% Source
Return

ButtonDestination:
FileSelectFolder,Destination,,0,Choose Destination
If Destination =
Return
GuiControl,,Edit2,% Destination
Return

ButtonCompare:
If Source =
Return
If Destination =
Return
Loop,%Source%\*,0,1
Files := A_Index
DF = 0
STrim := StrLen(Source)+1
Files := 100/Files
SetTimer,Prog,1000
LV_Delete()
Loop,%Source%\*,0,1
{
SSize := A_LoopFileSize
DFile := Destination SubStr(A_LoopFileLongPath,STrim)
FileGetSize,DSize,% DFile
GuiControl,,Edit1,% A_LoopFileLongPath
GuiControl,,Edit2,% DFile
CIndex := A_Index
GuiControl,,Button3,% DF "/" A_Index
If SSize != %DSize%
{
List .= A_LoopFileLongPath " - " SSize "`n" DFile " - " DSize "`n`n"
DF += 1
If SSize =
{
LV_Add("",A_LoopFileLongPath,"Missing")
Continue
}
If DSize =
{
LV_Add("",DFile,"Missing")
Continue
}
Else
LV_Add("",A_LoopFileLongPath,"Different")
}
}
GuiControl,,PG,100
SetTimer,Prog,Off
MsgBox,Done
Clipboard := List
GuiControl,,Edit1,% Source
GuiControl,,Edit2,% Destination
GuiControl,,Button3,Compare
Return

Prog:
GuiControl,,PG,% Files*CIndex
Return

GuiClose:
ExitApp[\code]

Re: Comparing folders?

Posted: 29 Dec 2018, 13:18
by jeeswg
- When comparing folders, I always do 2 loops.
- To discover which items are unique to folder A, and which items are unique to folder B.
- I either use FileExist repeatedly in both loops, which is potentially wasteful, or, I store all the information in arrays and loop through the arrays, which might involve a lot of storage.

Re: Comparing folders?

Posted: 29 Dec 2018, 13:52
by vsub
I thought of using two loops(I am doing them anyway)so I can add a variable(arrays seems too wasteful...I don't know why but I always try to use as less variables a possible)that creates a list for each folder but I still can't imagine it what exactly to do with those lists,how to make the rest of the code work as a want

Basically I want to create a list that contains different or missing files...maybe something like this

Code: Select all

Loop,%Source%\*,0,1
{
Files := A_Index
SList .= A_LoopFileLongPath "`n"
}
Loop,%Destination%\*,0,1
{
DFiles := A_Index
DList .= A_LoopFileLongPath "`n"
}

Loop,Parse,SList,`n
{
If DList not contains %A_LoopField%
Missing .= Destination SubStr(A_LoopField,StrLen(Source)+1) "`n"
}

Loop,Parse,DList,`n
{
If SList not contains %A_LoopField%
Missing .= Source SubStr(A_LoopField,StrLen(Destination)+1) "`n"
}

Sort,Missing
This will display all of the missing files(I don't really like the idea of scanning list more than thousand times for each item in the current list I am scanning)
But then what about the different files...this starts to look like a really long scan

Re: Comparing folders?

Posted: 30 Dec 2018, 04:04
by jeeswg
- I would use the new 'Loop Files' syntax, it's a bit more intuitive (using F/D/R instead of numbers), and is more forwards compatible.
Loop (files & folders) - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/LoopFile.htm
E.g. Loop, Files, %Source%\*, R
- I would use InStr instead of 'contains' because 'contains' will not work correctly for paths that contain commas.
E.g. if !InStr(vText, "`n" vNeedle "`n")
- And I would start any vText variable with an initial `n, before appending 'path and `n' to it for each path.

- Anyhow, InStr can be slow, so instead I would use arrays or a Scripting.Dictionary object.

Code: Select all

q:: ;2 folders - list unique/common files
vDir1 := "C:\Program Files"
vDir2 := "C:\Program Files (x86)"
vOutput1 := ""
VarSetCapacity(vOutput1, 1000000*2)
vOutput2 := ""
VarSetCapacity(vOutput2, 1000000*2)
vOutput3 := ""
VarSetCapacity(vOutput3, 1000000*2)
vLen1 := StrLen(vDir1)+2
vLen2 := StrLen(vDir2)+2

oDict := ComObjCreate("Scripting.Dictionary")
Loop, Files, % vDir1 "\*", FD
{
	vTemp := SubStr(A_LoopFileFullPath, vLen1)
	oDict.Item("" vTemp) := 1
}
Loop, Files, % vDir2 "\*", FD
{
	vTemp := SubStr(A_LoopFileFullPath, vLen2)
	if oDict.Exists("" vTemp)
		oDict.Item("" vTemp) := 0
		, vOutput3 .= vTemp "`r`n"
	else
		vOutput2 .= vTemp "`r`n"
}
for vKey in oDict
	if oDict.Item("" vKey)
		vOutput1 .= vKey "`r`n"
oDict := ""
Clipboard := "[unique to: " vDir1 "]`r`n" vOutput1 "`r`n" "[unique to: " vDir2 "]`r`n" vOutput2 "`r`n" "[present in both]`r`n" vOutput3
vOutput1 := vOutput2 := vOutput3 := ""
MsgBox, % "done"
return

Re: Comparing folders?

Posted: 17 May 2023, 19:46
by carno
jeeswg wrote:
30 Dec 2018, 04:04
- I would use the new 'Loop Files' syntax, it's a bit more intuitive (using F/D/R instead of numbers), and is more forwards compatible.
Loop (files & folders) - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/LoopFile.htm
E.g. Loop, Files, %Source%\*, R
- I would use InStr instead of 'contains' because 'contains' will not work correctly for paths that contain commas.
E.g. if !InStr(vText, "`n" vNeedle "`n")
- And I would start any vText variable with an initial `n, before appending 'path and `n' to it for each path.

- Anyhow, InStr can be slow, so instead I would use arrays or a Scripting.Dictionary object.

Code: Select all

q:: ;2 folders - list unique/common files
vDir1 := "C:\Program Files"
vDir2 := "C:\Program Files (x86)"
vOutput1 := ""
VarSetCapacity(vOutput1, 1000000*2)
vOutput2 := ""
VarSetCapacity(vOutput2, 1000000*2)
vOutput3 := ""
VarSetCapacity(vOutput3, 1000000*2)
vLen1 := StrLen(vDir1)+2
vLen2 := StrLen(vDir2)+2

oDict := ComObjCreate("Scripting.Dictionary")
Loop, Files, % vDir1 "\*", FD
{
	vTemp := SubStr(A_LoopFileFullPath, vLen1)
	oDict.Item("" vTemp) := 1
}
Loop, Files, % vDir2 "\*", FD
{
	vTemp := SubStr(A_LoopFileFullPath, vLen2)
	if oDict.Exists("" vTemp)
		oDict.Item("" vTemp) := 0
		, vOutput3 .= vTemp "`r`n"
	else
		vOutput2 .= vTemp "`r`n"
}
for vKey in oDict
	if oDict.Item("" vKey)
		vOutput1 .= vKey "`r`n"
oDict := ""
Clipboard := "[unique to: " vDir1 "]`r`n" vOutput1 "`r`n" "[unique to: " vDir2 "]`r`n" vOutput2 "`r`n" "[present in both]`r`n" vOutput3
vOutput1 := vOutput2 := vOutput3 := ""
MsgBox, % "done"
return
Thanks jeeswg, just what I was looking for!