verzeichnisse vergleichen Topic is solved

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: verzeichnisse vergleichen

19 Jan 2018, 09:29

Hmmm, ich habe mir das nicht runtergeladen, aber das Fenster legt nahe, dass das Tool genau zwei Verzeichnisse synchronisiert. Ist das so? Effel will ja wohl zwei Verzeichnisse vergleichen und ein drittes befüllen.
User avatar
divanebaba
Posts: 804
Joined: 20 Dec 2016, 03:53
Location: Diaspora

Re: verzeichnisse vergleichen

19 Jan 2018, 10:08

just me wrote:Hmmm, ich habe mir das nicht runtergeladen, aber das Fenster legt nahe, dass das Tool genau zwei Verzeichnisse synchronisiert. Ist das so? Effel will ja wohl zwei Verzeichnisse vergleichen und ein drittes befüllen.
Just me, Du hast wirklich ein Auge für Aufgabenstellungen. Stimmt, effel will gar nicht einfach nur synchronisieren, sondern schon etwas mehr, als das PathSync erfüllen kann. Aber mit einem bißchen hin- und herkopieren sollte das kein großes Ding sein.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: verzeichnisse vergleichen

19 Jan 2018, 10:11

Wo dann wieder AutoHotkey ins Spiel kommt, da es genau diese Aufgaben übernimmt.
Recommends AHK Studio
User avatar
divanebaba
Posts: 804
Joined: 20 Dec 2016, 03:53
Location: Diaspora

Re: verzeichnisse vergleichen  Topic is solved

19 Jan 2018, 10:38

Was soll ich dazu sagen? AHK ist unschlagbar. (Reimt sich sogar) :mrgreen: :mrgreen:

Ich würde bei einer solchen Aufgabenstellung folgendermaßen vorgehen, wobei wir bei der "verbale(n) Beschreibung der Lösung" wären.
Da ich nicht ausprobiert habe, in welcher Reihenfolge eine Loop (Dateien & Ordner)-Schleife die Dateien auflistet (erst die Ordner, dann die Dateien oder andersrum) sollte man vielleicht mit der Aufzählung (Erstellen einer Liste) mit Unterordnern anfangen.
Just me hat es erwähnt, erst die Ordnerstruktur erstellen, dann mit Dateien füllen, sonst Error :crazy: .
Diese Reihenfolge, erst die Unterordner aufzulisten, macht somit sogar Sinn.
Aber, jetzt kommt das große Aber, die Ordnerstruktur scheint unwichtig zu sein, da sämtliche Bilder vermutlich nur in einen einzigen Zielordner kopiert werden sollen.

Mehr kann ich, zum Kopiervorgang, ohne mehrmaliges wenn und dann, erstmal nicht beitragen.
Allerdings bietet es sich an, beim Auflisten der Dateien (nicht der Ordner) Eigenschaften (z.B. A_LoopFileSize, A_LoopFileTimeCreated etc.) direkt mit in den Namen zu schreiben. Siehe Beispiel#4 in der Hilfe, wo steht

Code: Select all

Dateiliste = %Dateiliste%%A_LoopFileTimeModified%`t%A_LoopFileName%`n ; Beispiel#4 in Hilfedatei
effel müsste es vielleicht so machen

Code: Select all

meineDateiListe = %meineDateiListe%_%A_LoopFileName%_%A_LoopFileSize%_%A_LoopFileTimeCreated%`n
oder ähnliches wählen.
Dann sollten, selbst bei gleichem Dateinamen, anhand der Dateigröße oder eines Zeitstempels, Dateien unterschieden werden können.
Das zu beschreiben ist fast genauso mühselig, wie einen Code zu erstellen. :mrgreen: :mrgreen:
Mehr Senf, wenn die Wurst soweit ist.
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: verzeichnisse vergleichen

19 Jan 2018, 11:43

Also, erst einmal der versprochene Minicrashkurs in Sachen "assoziative Arrays".

Vorwort:

Arrays im ursprünglichen Sinn sind Speicherbereiche, in denen Werte gleicher Länge (Felder / Elemente) lückenlos aufeinanderfolgend abgelegt sind. Die Größe des Bereichs und damit die Anzahl der maximal möglich Felder muss oft schon bei der Definition festgelegt. Der gesamte Bereich wird programmtechnisch über einen einzigen Zeiger (pointer) auf den Anfang des Bereichs verwaltet. Im Gegensatz dazu brauchen einzelne Variablen jeweils einen eigenen Zeiger auf den ihnen zugeordneten Speicherbereich. Man konnte deshalb in Zeiten knapper Ressourcen mit Arrays u.a. den von einem Programm zur Laufzeit benötigten Speicherplatz reduzieren.

Für den direkten Zugriff auf einzelne Elemente nutzt man einen sogenannten Index, der der Position bzw. der laufenden Nummer des Elements im Speicherbereich entspricht. Aus diesem Index wird die Differenz zum Anfang des Speicherbereichs zur Laufzeit errechnet. Diese Berechnung ist einfach, weil die Länge der einzelnen Elemente konstant ist. Für die Programmiersprache C, in der der Index des ersten Elements 0 ist, läuft das wie folgt:

Code: Select all

Elementadresse = Speicheradresse + (Index * Elementlänge)
AHK:

Die AHK-Doku unterscheidet zwischen "einfachen Arrays" und "assoziativen Arrays" (obwohl das technisch gesehen nicht wirklich stimmt):

Einfache Arrays:

Diese Arrays entsprechen bis auf die technische Implementierung am ehesten den obengenannten Arrays. Die Elemente werden über einen numerischen Index angesprochen. Der Index des ersten Elements ist bei AHK aber standarmäßig 1. Und es gibt noch weitere Unterschiede, z.B.:
  • Die Elemente dieser Arrays haben keinen festen Typ und damit auch keine feste Länge.
  • Diese Arrays sind dynamisch und kennen deshalb grundsätzlich keine Begrenzung für den minimalen oder maximalen Index.
Assoziative Arrays:

Assoziative Arrays enthalten Paare von zwei verknüpften (assoziierten) Werten. Dabei wird der erste Wert für den Zugriff auf das Element verwendet (Schlüssel / key), dem der zweite Wert zugewiesen ist (Wert / value). Ein klassisches Beispiel ist eine (einfache) "Übersetzungstabelle". Sie besteht aus Wortpaaren, bei denen z.B. einem englischen Wort die deutsche Übersetzung zugewiesen ist: one = eins, two = zwei, three = drei, .... In AHK kann man ein entsprechendes assoziatives Array wie folgt erstellen:

Code: Select all

; Objekt syntax (ja, AHK Arrays sind an sich Objekte):
EN_DE := {"one": "eins", "two": "zwei", "three": "drei", ...}
An den "Schlüssel" wird ein Doppelpunkt : angehängt, dann folgt der zugewiesen "Wert". Die einzelnen Wertepaare werden durch ein Komma , getrennt.

Code: Select all

; Array syntax
EN_DE := [] ; leeres Array erstellen
EN_DE["one"] := "eins"
EN_DE["two"] := "zwei"
EN_DE["three"] := "drei"
...
Hier wird der "Schlüssel" wie ein Index verwendet und das zugehörige Arrayelement wird erstellt. Diesem wird der hinter dem Zuweisungsoperator := stehende "Wert" zugewiesen.

Wertet man nun einen englischen Text Wort für Wort aus, kann man aus dem Array die deutsche Übersetzung abrufen:

Code: Select all

Englisch := "one"
Deutsch := EN_DE[Englisch]
MsgBox, %Englisch% = %Deutsch%
Die "Schlüssel" werden innerhalb des Arrays in alphabetischer Reihenfolge abgelegt. Man kannn diese Arrays deshalb auch für eine alphabetische Sortierung 'missbrauchen', indem man einem Array in beliebiger Reihenfolge "Schlüssel" hinzufügt. Ihr Wert ist dabei uninteressant. Wenn man hinterher das Array Element für Element abarbeitet, werden die "Schlüssel" in alphabetischer Reihenfolge zurückgegeben (siehe For-Schleife).

Wichtiger Hinweis: AHK unterscheidet bei den "Schlüsseln" nicht zwischen Gross- und Kleinschreibung. Wenn man das braucht, braucht es einige zusätzliche Verrenkungen.
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: verzeichnisse vergleichen

20 Jan 2018, 02:54

So, jetzt zum praktischen Teil. Das Skript versucht, das Problem mit assoziativen Arrays zu lösen. Es ist fast nicht getestet und mag Fehler enthalten. Deshalb ist es mehr eine Konzeptstudie als ein 'fertiges' Skript. Die enthaltenen Kommentare sollen das Prinzip verständlich machen:

Code: Select all

; gelöscht, neue Version im folgenden Beitrag
Last edited by just me on 20 Jan 2018, 06:12, edited 1 time in total.
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: verzeichnisse vergleichen

20 Jan 2018, 04:35

Nochmal ich!
Lesen, lesen und immer wieder lesen! :facepalm:
Jetzt habe ich die Aufgabenstellung aus den Augen verloren, als ich ein vorhandenes Skript mit ähnlichen Aufgaben komprimiert habe. Es geht natürlich auch mit zwei Schleifen. Einschränkungen wie oben:

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines, -1
; --------------------------------------------------------------------------------------------------------------------------------
; Pfade
QuellPfad1 := "E:\MeinKleinesVerzeichnis"
QuellPfad2 := "D:\MeinGroßesVerzeichnis"
ZielPfad   := "F:\MeinZielVerzeichnis"
; --------------------------------------------------------------------------------------------------------------------------------
; Startpositionen für die späteren SubStr() Aufrufe, mit denen die QuellPfade aus den Pfaden entfernt werden
StartPos1 := StrLen(QuellPfad1) + 2 ; Länge QuellPfad + 1 für den abschließenden Backslash ("\") + 1
StartPos2 := StrLen(QuellPfad2) + 2
; --------------------------------------------------------------------------------------------------------------------------------
; Arrays
QuellArray := [] ; leeres Array für die Namen aus QuellPfad1 anlegen.
VerzArray  := [] ; leeres Array für die neu zu erstellenden Verzeichnisse anlegen
; --------------------------------------------------------------------------------------------------------------------------------
; Zähler für kopierte Dateien
Zaehler := 0
; ================================================================================================================================
; Schleife über QuellPfad1 (kleines Verzeichnis) - Dateien in QuellArray eintragen
Loop, Files, %QuellPfad1%, FR
{
   ; Namen bilden
   ; Vom Verzeichnisnamen (A_LoopFileDir) wird nur der Teil nach dem Quellverzeichnis genommen
   Verzeichnis := SubStr(A_LoopFileDir, StartPos1)
   Datei := A_LoopFileName ; eigentlich überflüssig, nur zur Verdeutlichung
   ; Den Namen zusammensetzen
   If (Verzeichnis <> "") ; wenn Verzeichnis nicht leer ist
      Pfad := Verzeichnis . "\" . Datei
   Else
      Pfad := Datei
   ; Alternative Kurzfassung (ternary)
   ; Pfad := (Verzeichnis <> "" ? Verzeichnis . "\" : "") . Datei
   ; Namen als Schlüssel im Array speichern. Ein Wert wird nicht benötigt
   QuellArray[Pfad] := ""
}
; ================================================================================================================================
; Schleife über QuellPfad2 (großes Verzeichnis) - Dateien, die nicht in QuellArray eingetragen sind, werden kopiert
Loop, Files, %QuellPfad2%, FR
{
   ; Namen bilden
   ; Vom Verzeichnisnamen (A_LoopFileDir) wird nur der Teil nach dem Quellverzeichnis genommen
   Verzeichnis := SubStr(A_LoopFileDir, StartPos2)
   Datei := A_LoopFileName ; eigentlich überflüssig, nur zur Verdeutlichung
   ; Den Namen zusammensetzen
   If (Verzeichnis <> "") ; wenn Verzeichnis nicht leer ist
      Pfad := Verzeichnis . "\" . Datei
   Else
      Pfad := Datei
   ; Alternative Kurzfassung (ternary)
   ; Pfad := (Verzeichnis <> "" ? Verzeichnis . "\" : "") . Datei
   ; Wenn der Name im QuellArray abgelegt ist, passiert nichts.
   If QuellArray.HasKey(Pfad)
      Continue
   ; Datei kopieren
   ; Prüfen, ob ein Unterverzeichnis erstellt werden muss
   SplitPath, Pfad, Datei, Verzeichnis
   ; Wenn der Verzeichnisname noch nicht in VerzArray eingetragen ist, Verzeichnis erstellen und eintragen
   If (Verzeichnis <> "") && !VerzArray.HasKey(Verzeichnis) {
      FileCreateDir, %ZielPfad%\%Verzeichnis%
      VerzArray[Verzeichnis] := ""
   }
   ; Datei kopieren
   FileCopy, %QuellPfad2%\%Pfad%, %ZielPfad%\%Pfad%
   Zaehler++
}
; ================================================================================================================================
MsgBox, 0, Fertig!, %Zaehler% Dateien wurden kopiert!
ExitApp
effel
Posts: 542
Joined: 16 Jan 2018, 13:34

Re: verzeichnisse vergleichen

20 Jan 2018, 08:19

hallo just me,
danke für deinen super denkanstoss :-)

habe beide versionen getestet, es werden keine dateien kopiert, ich habe nur die pfade angepasst.

im verzeichnis:
QuellPfad1 := "C:\Users\effel\Desktop\meine_bilder"
liegen alle schon sortierten fotos.
und im verzeichnis:
QuellPfad2 := "C:\Users\effel\Desktop\neue_bilder"
liegen die zu vergleichenden neuen bilder
das verzeichnis:
ZielPfad := "C:\Users\effel\Desktop\Verzeichnis_Ziel"
ist und bleibt leer

Code: Select all

; Pfade
QuellPfad1 := "C:\Users\effel\Desktop\meine_bilder"
QuellPfad2 := "C:\Users\effel\Desktop\neue_bilder"
ZielPfad   := "C:\Users\effel\Desktop\Verzeichnis_Ziel"

Code: Select all

---------------------------
Fertig!
---------------------------
0 Dateien wurden kopiert!
---------------------------
OK   
---------------------------
effel
Posts: 542
Joined: 16 Jan 2018, 13:34

Re: verzeichnisse vergleichen

20 Jan 2018, 08:26

kann es an meiner ahk version liegen? habe bisher vermieden upzudaten, weil alles andere so dolle läuft


ahkversion = %A_Ahkversion%
msgbox % ahkversion

---------------------------
ahkversion.AHK
---------------------------
1.1.21.03
---------------------------
OK
---------------------------
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: verzeichnisse vergleichen

21 Jan 2018, 03:36

Moin,

nein, es sollte nicht an Dir liegen. Zunächst einmal habe ich in der letzten Version die Quellverzeichnisse 'logisch vertauscht'. Diesen Fehler hast Du aber mit der Belegung der Variablen schon korrigiert:

Code: Select all

QuellPfad1 := "C:\Users\effel\Desktop\meine_bilder" ; !!! 'großes Verzeichnis'  - Bestand !!!
QuellPfad2 := "C:\Users\effel\Desktop\neue_bilder"  ; !!! 'kleines Verzeichnis' - Neu !!!
Leider sind aber auch beide Loops nicht korrekt versorgt. Statt %QuellPfad1% muss da %QuellPfad1%\*.* stehen, sonst werden die Verzeichnisse überhaupt nicht durchlaufen. Also:

Code: Select all

Loop, Files, %QuellPfad1%\*.*, FR
...
Loop, Files, %QuellPfad2%\*.*, FR
...
Vielleicht sind auch noch weitere Fehler drin. Wir werden sehen.

Grüße,
just me
User avatar
divanebaba
Posts: 804
Joined: 20 Dec 2016, 03:53
Location: Diaspora

Re: verzeichnisse vergleichen

21 Jan 2018, 10:59

effel wrote:hallo just me,
danke für deinen super denkanstoss :-)
...
Denkanstoß??? :shock: :shock: Der Mann hat Deinen Job erledigt und nicht nur einen Hinweis gegeben. :crazy:
So einen Support wünsche ich mir auch. :D :D, allerdings bringen mich die Arrays bestimmt noch ins Grab.
effel
Posts: 542
Joined: 16 Jan 2018, 13:34

Re: verzeichnisse vergleichen

21 Jan 2018, 14:04

wunderbar, genau so war es gedacht. hut ab :-)

Code: Select all

/*
thema: Dateien, die nicht in QuellArray eingetragen sind, werden separiert
https://autohotkey.com/boards/viewtopic.php?f=9&t=42881
danke just me
*/


#NoEnv
#SingleInstance Force
SetBatchLines, -1

; ---------------------------------------------------------------
#NoEnv
Gui, Add, Button, w350 gQuellPfad1, Meine Bilder 
Gui, Add, Button, w350 gQuellPfad2, Neue Bilder  
Gui, Add, Button, w350 gZielPfad, Verzeichnis Ziel
Gui, Add, Button, w350 gstart, Start
Gui, Add, Button, w350 gGuiClose, Programm beenden
Gui, Show, , Ordnerinhalt vergleichen
; ---------------------------------------------------------------
Return
GuiClose:
GuiEscape:
ExitApp

; ---------------------------------------------------------------
QuellPfad1:
FileSelectFolder, QuellPfad1, , 3, Verzeichnis auswählen
return
; ---------------------------------------------------------------
QuellPfad2:
FileSelectFolder, QuellPfad2, , 3, Verzeichnis auswählen
return
; ---------------------------------------------------------------
ZielPfad:
FileSelectFolder, ZielPfad, , 3, Verzeichnis auswählen
return
------------------------------------------------------------------------------------------------------------------------

start:
; --------------------------------------------------------------------------------------------------------------------------------
; Startpositionen für die späteren SubStr() Aufrufe, mit denen die QuellPfade aus den Pfaden entfernt werden
StartPos1 := StrLen(QuellPfad1) + 2 ; Länge QuellPfad + 1 für den abschließenden Backslash ("\") + 1
StartPos2 := StrLen(QuellPfad2) + 2
; --------------------------------------------------------------------------------------------------------------------------------
; Arrays
QuellArray := [] ; leeres Array für die Namen aus QuellPfad1 anlegen.
VerzArray  := [] ; leeres Array für die neu zu erstellenden Verzeichnisse anlegen
; --------------------------------------------------------------------------------------------------------------------------------
; Zähler für kopierte Dateien
Zaehler := 0
; ================================================================================================================================
; Schleife über QuellPfad1 (kleines Verzeichnis) - Dateien in QuellArray eintragen
Loop, Files, %QuellPfad1%\*.*, FR
{
   ; Namen bilden
   ; Vom Verzeichnisnamen (A_LoopFileDir) wird nur der Teil nach dem Quellverzeichnis genommen
   Verzeichnis := SubStr(A_LoopFileDir, StartPos1)
   Datei := A_LoopFileName ; eigentlich überflüssig, nur zur Verdeutlichung
   ; Den Namen zusammensetzen
   If (Verzeichnis <> "") ; wenn Verzeichnis nicht leer ist
      Pfad := Verzeichnis . "\" . Datei
   Else
      Pfad := Datei
   ; Alternative Kurzfassung (ternary)
   ; Pfad := (Verzeichnis <> "" ? Verzeichnis . "\" : "") . Datei
   ; Namen als Schlüssel im Array speichern. Ein Wert wird nicht benötigt
   QuellArray[Pfad] := ""
}
; ================================================================================================================================
; Schleife über QuellPfad2 (großes Verzeichnis) - Dateien, die nicht in QuellArray eingetragen sind, werden kopiert
Loop, Files, %QuellPfad2%\*.*, FR
{
   ; Namen bilden
   ; Vom Verzeichnisnamen (A_LoopFileDir) wird nur der Teil nach dem Quellverzeichnis genommen
   Verzeichnis := SubStr(A_LoopFileDir, StartPos2)
   Datei := A_LoopFileName ; eigentlich überflüssig, nur zur Verdeutlichung
   ; Den Namen zusammensetzen
   If (Verzeichnis <> "") ; wenn Verzeichnis nicht leer ist
      Pfad := Verzeichnis . "\" . Datei
   Else
      Pfad := Datei
   ; Alternative Kurzfassung (ternary)
   ; Pfad := (Verzeichnis <> "" ? Verzeichnis . "\" : "") . Datei
   ; Wenn der Name im QuellArray abgelegt ist, passiert nichts.
   If QuellArray.HasKey(Pfad)
      Continue
   ; Datei kopieren
   ; Prüfen, ob ein Unterverzeichnis erstellt werden muss
   SplitPath, Pfad, Datei, Verzeichnis
   ; Wenn der Verzeichnisname noch nicht in VerzArray eingetragen ist, Verzeichnis erstellen und eintragen
   If (Verzeichnis <> "") && !VerzArray.HasKey(Verzeichnis) {
      FileCreateDir, %ZielPfad%\%Verzeichnis%
      VerzArray[Verzeichnis] := ""
   }
   ; Datei kopieren
   FileCopy, %QuellPfad2%\%Pfad%, %ZielPfad%\%Pfad%
   Zaehler++
}
; ================================================================================================================================
soundbeep, 1000, 1000
MsgBox, 0, Fertig!, %Zaehler% Dateien wurden kopiert!
ExitApp
/*
ich kann nur wachsen wenn ich auf den schultern von riesen stehe
just me ist einer von den vielen riesen in diesem forum :-) vielen dank
*/
User avatar
divanebaba
Posts: 804
Joined: 20 Dec 2016, 03:53
Location: Diaspora

Re: verzeichnisse vergleichen

21 Jan 2018, 20:12

effel wrote:...
/*
ich kann nur wachsen wenn ich auf den schultern von riesen stehe
just me ist einer von den vielen riesen in diesem forum :-) vielen dank
*/
Junge Pflanzen und Bäume wachsen, in der Regel, im Schatten der älteren Pflanzen auf.
Hol Dir also keinen Sonnenstich da oben :mrgreen: :mrgreen:

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 45 guests