Verzeichnisstruktur in Array einlesen

  • Hi leute,

    wiedermal ne Frage. Mit dem DOS-Befehl "dir" kann man ja, mit den entsprechenden Attributen, eine Verzeichnisstruktur (mit allen Unterverzeichnissen und Files) in ein (Temp-)File schreiben. Anschließend könnte man dieses File mit _FileReadToArray() in ein Array einlesen. Kennt jemand ne Möglichkeit, bei der man um die Erstellung dieses Tempfiles drum rum kommt?

    Gtruß, Steff

  • Jo, war auch schon ein Ansatz von mir. Ich dachte aber es geht vllt. etwas einfacher (bereits vorhandene UDF). Trotzdem vielen Dank!

    • Offizieller Beitrag

    Es hat mich mal interessiert, wie lange AutoIt für so eine rekursive Liste benötigt. :rolleyes:

    Eines vorweg: Benutzt das Script nicht im Hauptpfad. Das dauert ewig. Bei moderateren Pfadverhältnissen funktioniert es aber recht gut.

    Spoiler anzeigen
    [autoit]


    #Include <File.au3>
    #Include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $aFileList[1]
    Global $fpath = 'D:\AutoIt\'
    SplashTextOn('Recursive FileList', $fpath, 800, 50, -1, -1, 52)
    $fFileList = _FileListToArray($fpath, '*.*', 1)
    If IsArray($fFileList) Then
    $prev = UBound($aFileList)-1
    ReDim $aFileList[$prev+1+$fFileList[0]]
    For $j = 1 To $fFileList[0]
    $aFileList[$prev+$j] = $fpath & $fFileList[$j]
    Next
    EndIf
    _ReFileListToArray($fpath)
    SplashOff()
    _ArrayDisplay($aFileList,'$FileList')

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _ReFileListToArray($path)
    ControlSetText('Recursive FileList', '', 'Static1', ' ' & UBound($aFileList)-1 & ' ' & $path)
    Local $dFileList = _FileListToArray($path, '*', 2)
    If IsArray($dFileList) Then
    For $i = 1 To $dFileList[0]
    $fFileList = _FileListToArray($path & $dFileList[$i] & '\', '*.*', 1)
    If IsArray($fFileList) Then
    $prev = UBound($aFileList)-1
    ReDim $aFileList[$prev+1+$fFileList[0]]
    For $j = 1 To $fFileList[0]
    $aFileList[$prev+$j] = $path & $dFileList[$i] & '\' & $fFileList[$j]
    Next
    EndIf
    _ReFileListToArray($path & $dFileList[$i] & '\')
    Next
    EndIf
    EndFunc

    [/autoit]

    Verbesserungsvorschläge bzw. Geschwindigkeitsoptimierungen sind sehr willkommen. :D

    Edit: Diese Version ist etwas schneller.

  • Oscar
    Die Performance-Bremse ist prinzipiell das Array selbst.
    Jedesmal wenn per _ArrayAdd ein Element hinzugefügt wird muss ein neuer Bereich im Speicher allokiert werden welcher Platz für das nun größer gewordene Array bietet.
    Dann muss das gesamte Array in diesen Speicherbereich kopiert werden.
    Jedesmal
    Je mehr Elemente im Array sind umso länger dauert die Prozedur.
    Deswegen schlage ich vor in diesem Fall auf eine andere Datenstruktur als ein Array auszuweichen.
    Eine dynamische Datenstruktur bei welcher die Elemente nicht hintereinander im Speicher stehen müssen sondern frei verteilt sein können und damit problemlos Elemente hinzugefügt oder entfernt werden können.
    Hab dafür eine ArrayList genommen:

    Spoiler anzeigen
    [autoit]

    Global $fpath = @HomeDrive & '\'

    [/autoit] [autoit][/autoit] [autoit]

    Global $FileList = _FileListToArrayList($fpath, '*', 0)
    If Not @error Then _ArrayListDisplay($FileList)


    ;===============================================================================
    ;
    ; Description: lists all files and folders recursive in a specified path
    ; Syntax: _FileListToArrayList($Path, $Filter = "*", $Flag = 0)
    ; Parameter(s): $Path = Path to generate filelist for
    ; $Filter = The filter to use. Search the Autoit3 manual for the word "WildCards" For details
    ; $Flag = determines weather to return file or folders or both
    ; $iFlag=0(Default) Return both files and folders
    ; $iFlag=1 Return files Only
    ; $iFlag=2 Return Folders Only
    ; $CaseSensitive = casesensitive Filter - True or False
    ;
    ; Requirement(s): .Net-FrameWork
    ; Return Value(s): On Success - Returns an Array-List Object containing the list of files and folders in the specified path
    ; On Failure - Returns the an empty string "" if no files are found and sets @Error on errors
    ; @Error=1 Failure Creating the ArrayList-Object
    ; @Error=2 Failure Creating the FileSystem-Object
    ; @Error=3 Invalid $Flag
    ; @Error=4 $Path don´t exists
    ;
    ; Author(s): AspirinJunkie <AspirinJunkie at german-nlite dot de>
    ; Note(s): -
    ;===============================================================================

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayList($Path, $Filter = '*', $Flag = 0, $CaseSensitive = False)
    Local $Replaces[8][2] = [['.', '\.' ], ['*', '.*' ], ['?', '.' ], ['+', '\+' ], ['-', '\-' ], ['(', '\(' ], [')', '\)' ], ['[', '\[' ]]
    Local $Folder, $e, $Case
    Local $ArrayList = ObjCreate("System.Collections.ArrayList")
    If @error Or Not IsObj($ArrayList) Then Return SetError(1, 1, 0)
    Local $FSObj = ObjCreate('Scripting.FileSystemObject')
    If @error Or Not IsObj($ArrayList) Then Return SetError(2, 2, 0)

    If Not ($Flag = 0 Or $Flag = 1 Or $Flag = 2) Then Return SetError(3, 3, '')
    If Not $FSObj.FolderExists($Path) Then Return SetError(4, 4, '')

    SplashTextOn('Recursive FileList', $Path, 800, 50, -1, -1, 36)

    For $i = 0 To 7
    $Filter = StringReplace($Filter, $Replaces[$i][0], $Replaces[$i][1])
    Next
    If Not $CaseSensitive Then $Case = '(?i)'

    If StringRight($Path, 1) <> '\' Then $Path &= '\'

    $Folder = $FSObj.GetFolder($Path)

    If $Flag < 2 Then
    For $e In $Folder.Files
    If StringRegExp($e.Name, $Case & $Filter) Then $ArrayList.add($Path & $e.Name)
    Next
    EndIf

    For $e In $Folder.SubFolders
    If $Flag <> 1 Then
    If StringRegExp($e.Name, $Case & $Filter) Then $ArrayList.add($Path & $e.Name)
    EndIf
    _FileListToArrayListExtended($Path & $e.Name & '\', $Filter, $Flag, $Case, $ArrayList, $FSObj )
    Next

    SplashOff()

    Return $ArrayList
    EndFunc ;==>_FileListToArrayList

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayListExtended($Path, $Filter, $Flag, $Case, ByRef $ArrayList, ByRef $FSObj)
    Local $Folder

    ControlSetText('Recursive FileList', '', 'Static1', ' ' & $Path)

    $Folder = $FSObj.GetFolder($Path)

    If $Flag < 2 Then
    For $e In $Folder.Files
    If StringRegExp($e.Name, $Case & $Filter) Then $ArrayList.add($Path & $e.Name)
    Next
    EndIf

    For $e In $Folder.SubFolders
    If $Flag <> 1 Then
    If StringRegExp($e.Name, $Case & $Filter) Then $ArrayList.add($Path & $e.Name)
    EndIf
    _FileListToArrayListExtended($Path & $e.Name & '\', $Filter, $Flag, $Case, $ArrayList, $FSObj)
    Next
    EndFunc ;==>_FileListToArrayListExtended
    ;===============================================================================

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _ArrayListDisplay(ByRef $ArrayList)
    Local $Opt = Opt("GUIOnEventMode", 0)
    Local $GUI = GUICreate("ArrayList", 572, 536)
    Local $ListView = GUICtrlCreateListView("Element|Wert", 8, 8, 553, 481)
    Local $Button = GUICtrlCreateButton("O.k.", 208, 496, 121, 33, 0)
    Local $counter = 1

    [/autoit] [autoit][/autoit] [autoit]

    For $e In $ArrayList
    GUICtrlCreateListViewItem($counter & '|' & $e, $ListView)
    $counter += 1
    Next
    GUISetState(@SW_SHOW)

    Do
    Switch GUIGetMsg()
    Case -3
    ExitLoop
    Case $Button
    ExitLoop
    EndSwitch
    Until 0
    GUIDelete($GUI)
    Opt("GUIOnEventMode", $Opt)
    EndFunc

    [/autoit]

    Hinweis: Die _ArrayListDisplay-Funktion kann momentan nur rund 4000 Elemente anzeigen.
    Nicht wundern also wenn anscheinend zu wenig Elemente gefunden wurden - in der ArrayList selbst sind alle vorhanden.

    3 Mal editiert, zuletzt von AspirinJunkie (6. Februar 2008 um 21:11)

    • Offizieller Beitrag

    AspirinJunkie: Ja, das mit _ArrayAdd ist mir auch schon aufgefallen und das habe ich bei meiner Version bereits korrigiert und das führt auch schon zu einer Geschwindigkeitssteigerung.

    Deine Version ist wirklich schnell, aber mit der Anzeige stimmt etwas nicht. Die geht nur bis Element 4094 (bei C:\Dokumente und Einstellungen...). Das Script scannt aber alles durch, das kann man ja anhand des SplashText sehen.

  • Hatte vorhin noch einen Hinweis mit dazu geschrieben ;) :

    Hinweis: Die _ArrayListDisplay-Funktion kann momentan nur rund 4000 Elemente anzeigen.
    Nicht wundern also wenn anscheinend zu wenig Elemente gefunden wurden - in der ArrayList selbst sind alle vorhanden.

    Die AutoIt eigene Funktion GUICtrlCreateListViewItem scheint auf eine bestimmte Anzahl an Elementen beschränkt zu sein.
    Könnte man wie es bei ArrayDisplay auch gemacht wurde auf _GUICtrlListView_InsertItem ausweichen.
    War aber eh nur schnell als Beispiel geschrieben um eine ArrayList zu visualisieren.
    Prinzipiell sollte man aber auch hier wegen des Memory-Leaks von AutoIt bei Objektvariablen überlegen ob man die ArrayList und das FileSystemObject global erstellt, anstatt lokal und dann als Parameter übergibt, wenn man die Funktion mehrmals aufrufen will.

    • Offizieller Beitrag

    Ich habe noch eine andere Version geschrieben, die einen String als Speicher benutzt. Jetzt kann man auch den Hauptpfad angeben, denn dieses Script ist richtig schnell. :)

    Spoiler anzeigen
    [autoit]


    #Include <GUIConstants.au3>
    #Include <File.au3>
    #Include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate('Recursive FileList', 800, 600, -1, -1)
    $label = GUICtrlCreateLabel('', 5, 10, 790, 30)
    $edit1 = GUICtrlCreateEdit('', 5, 45, 790, 540)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    Global $Files = '', $count
    Global $fpath = 'C:\Programme\AutoIt3\'

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSetData($label, $fpath)

    [/autoit] [autoit][/autoit] [autoit]

    $start = TimerInit()

    [/autoit] [autoit][/autoit] [autoit]

    _FileListToString($fpath)

    [/autoit] [autoit][/autoit] [autoit]

    $diff = TimerDiff($start)

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSetData($edit1, StringReplace($Files, '|', @CRLF))
    GUICtrlSetData($label, Round($diff/1000, 3) & ' sek. / ' & $count & ' Dateien')

    [/autoit] [autoit][/autoit] [autoit]

    Global $aFileList = StringSplit($Files, '|'); Array $aFileList enthält Auflistung aller Dateien inkl. Pfad
    ;_ArrayDisplay($aFileList)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToString($path)
    Local $hSearch, $sFile
    $hSearch = FileFindFirstFile($path & '*.*')
    If $hSearch <> -1 Then
    While 1
    $sFile = FileFindNextFile($hSearch)
    If @error Then
    SetError(0)
    ExitLoop
    EndIf
    If StringInStr(FileGetAttrib($path & $sFile), "D") <> 0 Then ContinueLoop
    $count += 1
    $Files &= $path & $sFile & '|'
    WEnd
    FileClose($hSearch)
    EndIf
    _ReFileListToString($path)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _ReFileListToString($path)
    GUICtrlSetData($label, ' ' & $path)
    Local $dFileList = _FileListToArray($path, '*', 2)
    If IsArray($dFileList) Then
    For $i = 1 To $dFileList[0]
    Local $hSearch, $sFile
    $hSearch = FileFindFirstFile($path & $dFileList[$i] & "\" & '*.*')
    If $hSearch <> -1 Then
    While 1
    $sFile = FileFindNextFile($hSearch)
    If @error Then
    SetError(0)
    ExitLoop
    EndIf
    If StringInStr(FileGetAttrib($path & $dFileList[$i] & "\" & $sFile), "D") <> 0 Then ContinueLoop
    $count += 1
    $Files &= $path & $dFileList[$i] & "\" & $sFile & '|'
    WEnd
    FileClose($hSearch)
    EndIf
    _ReFileListToString($path & $dFileList[$i] & '\')
    Next
    EndIf
    EndFunc

    [/autoit]

    Edit: Es ging ja darum ein Array mit den Dateien zu erstellen, deswegen habe ich das mal entsprechend angepasst.

  • Also wenn´s wirklich nur auf eine Auflistung aller Dateien geht dann bekomm ich meins auch noch ein ganzes Stückchen schneller:

    Spoiler anzeigen
    [autoit]

    Global $fpath = 'C:\'

    [/autoit] [autoit][/autoit] [autoit]

    $start = TimerInit()
    Global $FileList = _FileListToArrayList($fpath)
    $diff = TimerDiff($start)
    _ArrayListDisplay($FileList)
    MsgBox(0,"", Round($diff/1000, 3) & ' sek. / ' & $FileList.count & ' Dateien')

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayList($Path)
    Local $SHandle, $File
    Local $ArrayList = ObjCreate("System.Collections.ArrayList")
    If @error Or Not IsObj($ArrayList) Then Return SetError(1, 1, 0)
    If Not FileExists($Path) Then Return SetError(2, 2, $ArrayList)

    SplashTextOn('Recursive FileList', $Path, 800, 50, -1, -1, 36)

    $SHandle = FileFindFirstFile($Path & '*.*')
    If @error Then Return SetError(3, 3, $ArrayList)
    Do
    $File = FileFindNextFile($SHandle)
    If @error Then ExitLoop

    If StringInStr(FileGetAttrib($Path & $File), 'D') Then
    _FileListToArrayListExtended($Path & $File & '\', $ArrayList)
    Else
    $ArrayList.add($Path & $File)
    EndIf
    Until 0
    FileClose($SHandle)
    SplashOff()

    Return $ArrayList
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayListExtended($Path, ByRef $ArrayList)
    Local $Folder

    ControlSetText('Recursive FileList', '', 'Static1', ' ' & $Path)

    $SHandle = FileFindFirstFile($Path & '*.*')
    If @error Then Return SetError(3, 3, $ArrayList)
    Do
    $File = FileFindNextFile($SHandle)
    If @error Then ExitLoop
    If StringInStr(FileGetAttrib($Path & $File), 'D') Then
    _FileListToArrayListExtended($Path & $File & '\', $ArrayList)
    Else
    $ArrayList.add($Path & $File)
    EndIf
    Until 0
    FileClose($SHandle)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArrayListDisplay(ByRef $ArrayList)
    Local $Opt = Opt("GUIOnEventMode", 0)
    Local $GUI = GUICreate("ArrayList", 572, 536)
    Local $Edit = GUICtrlCreateEdit("", 8, 8, 553, 481)
    Local $Button = GUICtrlCreateButton("O.k.", 208, 496, 121, 33, 0)
    Local $counter = 1
    Local $String

    For $e In $ArrayList
    $String &= StringFormat("% 6d %s", $counter, $e) & @CRLF
    $counter += 1
    Next
    GUICtrlSetData($Edit, $String)

    GUISetState(@SW_SHOW)

    Do
    Switch GUIGetMsg()
    Case - 3
    ExitLoop
    Case $Button
    ExitLoop
    EndSwitch
    Until 0
    GUIDelete($GUI)
    Opt("GUIOnEventMode", $Opt)
    EndFunc

    [/autoit]


    Wobei mir deine Variante bei der Ausgabe besser gefällt da dort immer erst die Dateien und dann die Ordner angezeigt werden.
    Könnte ich auch noch machen - würde aber Speed fressen... ;)

    Mir persönlich ist aber meine erste Version noch am liebsten da man dort ja noch flexibel ist ob man nur Ordner oder Dateien oder beides haben möchte.
    Außerdem kann man ja noch einen Filter einsetzen.

    • Offizieller Beitrag

    Das stimmt schon, aber im Ursprungsposting ging es ja um ein Array mit allen Dateien inkl. Unterordner. Hab mein Script in Posting '10' entsprechend angepasst.
    Die Idee mit dem String ist mir gekommen, als ich die 'Beschränkung' für String-Datentypen gelesen hatte (Can contain strings of up to 2147483647 characters). Ich bin mir nur nicht ganz sicher wegen der Rekursionstiefe von AutoIt (=5100). Kann man diese Grenze sprengen oder tritt vorher eine Limitierung durch das Dateisystem auf?

  • Hi, hab das Ganze hier nicht komplett mit verfolgt, wollte mich aber auch mal dran versuchen:

    Mein Ziel: Dateien rekursiv listen ohne externe Hilfsmittel (Objekte, UDFs etc.)

    Folgendes ist dabei heraus gekommen:

    Spoiler anzeigen
    [autoit]

    #include "Array.au3"

    [/autoit] [autoit][/autoit] [autoit]

    main()

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItStart()
    #NoTrayIcon
    Opt("MustDeclareVars", 1)
    EndFunc ;==>OnAutoItStart

    [/autoit] [autoit][/autoit] [autoit]

    Func main()
    Local $as_files = 0
    Local $n_timer = TimerInit()
    _FileListToArrayRecursive("C:\WINNT\system32", $as_files)
    MsgBox(64, "_FileScan", Round(TimerDiff($n_timer) / 1000, 4) & ' seconds / ' & $as_files[0] & " files")
    _ArrayDisplay($as_files)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Function Name.....: _FileListToArrayRecursive
    ; Description.......: Lists all files of a specified path recursively.
    ; Version...........: 1.0
    ; Change Date.......: 2008-02-07
    ; AutoIt Version....: 3.2.10.0
    ;
    ; Parameter(s)......: $s_path - String containing the path.
    ; $as_files - Array containing the file paths.
    ; Requirements(s)...: None
    ; Return Value(s)...: Success: Returns 1
    ; Failure: Returns 0 if the path does not exist.
    ;
    ; Author(s).........: teh_hahn
    ; Company...........: None
    ; URL...............: None
    ; Note(s)...........: None
    ;===============================================================================
    Func _FileListToArrayRecursive($S_PATH, ByRef $as_files)
    If Not FileExists($S_PATH) Then Return (0)
    If StringRight($S_PATH, 1) = "\" Then $S_PATH = StringTrimRight($S_PATH, 1)
    If Not IsArray($as_files) Then Dim $as_files[1] = [0]
    Local $i = 0, $h_search = -1, $s_file = "", $s_fpath = ""

    [/autoit] [autoit][/autoit] [autoit]

    $h_search = FileFindFirstFile($S_PATH & "\*")
    While 1
    $s_file = FileFindNextFile($h_search)
    If @error Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    $s_fpath = $S_PATH & "\" & $s_file
    If StringInStr(FileGetAttrib($s_fpath), "D") Then
    _FileListToArrayRecursive($s_fpath, $as_files)
    Else
    $i = ($as_files[0] + 1)
    ReDim $as_files[$i + 1]
    $as_files[0] = $i
    $as_files[$i] = $s_fpath
    $i += 1
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($h_search)
    Return (1)
    EndFunc ;==>_FileListToArrayRecursive

    [/autoit]

    Vorteile:
    - Schlanker Code
    - Keine globalen Variablen
    - Keine Code-Redundanzen
    - Keine externen Hilfsmittel

    Nachteile:
    - Geschwindigkeit :( </sPiTsHiT@gmx.de></Array.au3>

    Also, wie kann man speziell diese Funktion (ohne die Vorteile zu verlieren!) verbessern? Bin gespannt!!!
    <Array.au3><sPiTsHiT@gmx.de>
    AspirinJunkie: Echt krass, wie schnell das mit Listen geht!!!

  • Wie Oscar schon sagte ist das ReDim das Problem.
    Optimierungen müssten also in die Richtung gehen diese zu minimieren.
    Also vorstellbar wäre das z.b. in jedem Verzeichnis erst gezählt wird wie viele Dateien vorhanden sind und für alle ein entsprechend groß dimensioniertes ReDim durchgeführt wird.
    Eine deutlich schnellere aber nicht empfehlenswerte Variante wäre aber noch ein Array schon ausreichend groß zu dimensionieren (sagen wir mal 50.000 Elemente) und erst am Ende das auf die entsprechende Größe zu runterzu-"ReDimmen" ( ;) ) so das man nur ein einziges ReDim durchführt.
    Davon ist allerdings abzuraten wegen der sinnlosen Speicherverschwendung und für den Fall das es mal mehr Elemente werden als die 50.000.
    Aber allemal interessant um den Geschwindigkeitsunterschied zu sehen...

  • Hi,

    hab mich mal dran versucht, ich hab aber wohl einen logischen Fehler drin, vielleicht könnt Ihr ja helfen. Bei dieser Version soll er das Array jeweils nur ReDimmen, wenn ein Verzeichnis erkannt wird und anhand der Anzahl von Dateien im Verzeichnis die Größe neu setzen:

    Spoiler anzeigen
    [autoit]

    Local $n_timer = TimerInit()
    Local $v_ret = _FileListToArrayRecursive($S_PATH, $as_files)
    _ArrayDisplay($as_files, "Runtime: " & Round((TimerDiff($n_timer) / 1000), 4) & " seconds")
    _DebugFunc($v_ret, "_FileListToArrayRecursive")

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileListToArrayRecursive($S_PATH, ByRef $as_files)
    If Not FileExists($S_PATH) Then Return (0)
    If StringRight($S_PATH, 1) = "\" Then $S_PATH = StringTrimRight($S_PATH, 1)
    Local $i = 0, $h_search = -1, $s_file = "", $s_fpath = "", $i_count = 0, $av_dirsize = 0

    If Not IsArray($as_files) Then
    $av_dirsize = DirGetSize($S_PATH, 3)
    If IsArray($av_dirsize) Then
    Dim $as_files[($av_dirsize[1] + 1)] = [0]
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $i = $as_files[0]
    $h_search = FileFindFirstFile($S_PATH & "\*")
    While 1
    $s_file = FileFindNextFile($h_search)
    If @error Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    $s_fpath = $S_PATH & "\" & $s_file
    If StringInStr(FileGetAttrib($s_fpath), "D") Then
    $av_dirsize = DirGetSize($s_fpath, 3)
    If IsArray($av_dirsize) Then
    If $av_dirsize[1] Then
    $i_count = ($as_files[0] + $av_dirsize[1])
    MsgBox(0, "$s_fpath", "Index 0: " & $as_files[0] & @CR & "Files: " & $av_dirsize[1] & @CR & "Total: " & $i_count)
    $as_files[0] = $i_count
    ReDim $as_files[$i_count]
    EndIf
    ;~ _FileListToArrayRecursive($s_fpath, $as_files)
    EndIf
    Else
    $i += 1
    $as_files[0] = $i
    $as_files[$i] = $s_fpath
    ConsoleWrite($i & " = " & $s_fpath & @CR)
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($h_search)
    Return (1)
    EndFunc ;==>_FileListToArrayRecursive

    [/autoit]

    Problem ist, dass irgendwan der Index-0 des Arrays kleiner wird! Ich seh den Fehler grade nicht!

  • Machs doch so, Das Redim am Anfang, nicht irgendwo dazwischen, also jedes mal, wenn die Funktion aufgerufen wird!

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name.....: _FileListToArrayRecursive
    ; Description.......: Lists all files of a specified path recursively.
    ; Version...........: 1.0
    ; Change Date.......: 2008-02-07
    ; AutoIt Version....: 3.2.10.0
    ;
    ; Parameter(s)......: $s_path - String containing the path.
    ; $as_files - Array containing the file paths.
    ; Requirements(s)...: None
    ; Return Value(s)...: Success: Returns 1
    ; Failure: Returns 0 if the path does not exist.
    ;
    ; Author(s).........: teh_hahn
    ; Company...........: None
    ; URL...............: None
    ; Note(s)...........: None
    ;===============================================================================
    Func _FileListToArrayRecursive($S_PATH, ByRef $as_files)
    If Not FileExists($S_PATH) Then Return (0)
    If StringRight($S_PATH, 1) = "\" Then $S_PATH = StringTrimRight($S_PATH, 1)
    If Not IsArray($as_files) Then Dim $as_files[1] = [0]
    Local $i = 0, $h_search = -1, $s_file = "", $s_fpath = ""

    [/autoit] [autoit][/autoit] [autoit]

    $h_search = FileFindFirstFile($S_PATH & "\*")

    [/autoit] [autoit][/autoit] [autoit]

    ; REDIM Block
    Local $temp = DirGetSize($S_PATH,3)
    If IsArray($as_files) Then
    $temp = (UBound($as_files)+$temp[1])
    If $temp = 0 Then $temp = 1
    ReDim $as_files[$temp]
    Else
    Dim $as_files[$temp[1]+1] = [0]
    EndIf
    ;REDIM ENde

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $s_file = FileFindNextFile($h_search)
    If @error Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    $s_fpath = $S_PATH & "\" & $s_file
    If StringInStr(FileGetAttrib($s_fpath), "D") Then
    _FileListToArrayRecursive($s_fpath, $as_files)
    Else
    $i = ($as_files[0] + 1)
    ;ReDim $as_files[$i + 1]
    $as_files[0] = $i
    $as_files[$i] = $s_fpath
    $i += 1
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($h_search)
    Return (1)
    MsgBox(0, '', "")
    EndFunc ;==>_FileListToArrayRecursive

    [/autoit]

    //Edit: Dauer: 31 Sekunden, 17016 Dateien
    0,1 Sekunden: 510 Dateien -> Schneller als mit ArrayList von AspirinJunkie :) Dauert 0,14 Sek.

    2 Mal editiert, zuletzt von progandy (8. Februar 2008 um 11:22)

  • Ich glaube Oscar ist nicht zu toppen :)
    Oscar / 36633 Dateien = 16,497 Sek.
    Oscar / 13378 Dateien = 2,919 Sek.
    progandy / 13378 Dateien = 17,16 Sek.

    Mfg
    Jens (McPoldy)

    Twitter: jkroeger

    Denn die Dinge, die wir erst lernen müssen, bevor wir sie tun, lernen wir beim Tun.(Aristoteles)

    • Offizieller Beitrag

    McPoldy: Vorsicht mit Vergleichsmessungen. Hier spielt nicht nur das Script eine Rolle. Und auch auf ein und demselben PC, also mit der gleichen Hardware, sollte man den Festplatten-Cache nicht vergessen. Bei mir ergibt sich ein gewaltiger Unterschied, ob man das Script mit z.B. C:\ einmal aufruft oder gleich zweimal. Beim zweiten Mal scheint es so, als würde ein Großteil der Daten aus dem Cache gelesen werden, denn die Zeiten sind deutlich kürzer.

    Das sollte man bei Messungen berücksichtigen.