Comparing folders?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
vsub
Posts: 541
Joined: 29 Sep 2015, 03:39

Comparing folders?

29 Dec 2018, 11:25

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]
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Comparing folders?

29 Dec 2018, 13:18

- 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.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
vsub
Posts: 541
Joined: 29 Sep 2015, 03:39

Re: Comparing folders?

29 Dec 2018, 13:52

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
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Comparing folders?

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
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
carno
Posts: 265
Joined: 20 Jun 2014, 16:48

Re: Comparing folders?

17 May 2023, 19:46

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!

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Leonardo_Portela and 183 guests