Anfänger braucht Hilfe beim einlesen von Dateien

  • Guten Abend zusammen :)

    Ich habe da ein kleinen Problem und hoffe ihr könnt mir da Helfen ^^
    Ich versuche mir gerade AutoIT wieder beizubringen und stehe aktuell vor dem Problem das ich eine .txt nur umständlich einlesen kann.

    Die Ausgangsdatei sieht so aus:

    Spoiler anzeigen

    name model serialnumber size partitions
    ---- ----- ------------ ---- ----------
    \\.\PHYSICALDRIVE0 Samsung SSD 830 EVO 250GB
    \\.\PHYSICALDRIVE2 Samsung SSD 840 PRO Series
    \\.\PHYSICALDRIVE1 Samsung SSD 830 EVO 500GB
    \\.\PHYSICALDRIVE3 Multi Flash Reader USB Device

    Aktuell lese ich die Daten so ein:



    Die Frage die sich mir stellt, mache ich das so richtig?
    Bzw. gibt es eine einfachere Methode?

    Ich brauche ja für jede HDD einen anderen Suchtext, bei HDD1 wäre es ja "\\.\PHYSICALDRIVE1"
    Ich habe quasi 10 dieser Blöcke untereinander stehen mit anderem Suchtext und anderer Schluss Variable um mir die Daten in verschiedene Variablen schreiben zu lassen.

    Das Ergebnis möchte ich mir anschließend in einem Fenster anzeigen lassen

    Vielen Dank im Voraus

    Blue-Twoo

  • Wenn du FileOpen verwendest, denke auch am Ende an FileClose.
    Ich verwende zum einlesen der Datei immer _FileReadToArray.
    Was nun besser ist kann ich dir aber nicht sagen.

  • Nimm's mir nicht übel, aber das liest sich grausam. :D
    Wenn du gerade erst eingestiegen bist, ist das aber total normal. Du solltest anfangs vielleicht erstmal deinen Lösungsansatz in Pseudocode (ruhig auf Deutsch!) niederschreiben. Also, zum Beispiel so:

    Code
    1. Datei einlesen
    2. HDD suchen
    3. Wenn vorhanden, dann Bezeichnung auslesen

    Dazu kommt, dass jeder Dateizugriff Verschwendung von Ressourcen ist. Es gibt eigentlich keinen Grund, warum man mehrmals auf die selbe Datei zugreifen sollte - der Inhalt bleibt ja der selbe, oder? Auch, wenn AutoIt/Windows durch internes Caching diese mehrfachen Zugriffe im Hintergrund unterbindet, ist es kein schöner und guter Stil. Ein Zugriff reicht, dann können wir mit Variablen arbeiten. Auch mehrfach genau den selben Befehl auszuführen macht in diesem Sachzusammenhang keinen Sinn ($readline = FileReadLine($HDD_Liste_Auslesen, $i) und Local $line = FileReadLine($HDD_Liste, $i)). Hier spricht man im Fachjargon von Redundanz, also überflüssiger Information.

    Das findet sich in deinem Skript noch öfter wieder. $HDD0 und $str haben immer den selben Wert, $suchzeile und $i (nicht ganz, aber in allen relevanten Fällen) ebenso. Das sollten wir vermeiden.

    Da du diesen Codeblock ja mehrmals ausführen möchtest, würde sich außerdem anbieten, funktional zu programmieren. Das heißt, man erstellt eine Funktion, der man einen Parameter übergeben kann. Ich übergebe beispielsweise "\\.\PHYSICALDRIVE4" und die Funktion setzt an den richtigen Stellen den Wert ein. Das Konzept ist ohne Beispiel relativ schwer erklärbar, verhindert aber, dass du den selben Codeblock zehn mal wiederholen musst. Denn auch das ist nichts anderes als Redundanz. ;)


    Ich habe mal eine solche Funktion auf Basis einfacher String-Funktionen entworfen und umfangreich kommentiert. Sie basiert auf dem o.g. Pseudocode und ist hoffentlich nachvollziehbar. Vielleicht hilft dir das ja.

    [autoit]


    #include <File.au3>

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

    ;- -- --- Nur zum Testen --- -- -
    Local $sTestData = "\\.\PHYSICALDRIVE0 Samsung SSD 830 EVO 250GB" & @CRLF & _
    "\\.\PHYSICALDRIVE2 Samsung SSD 840 PRO Series" & @CRLF & _
    "\\.\PHYSICALDRIVE1 Samsung SSD 830 EVO 500GB" & @CRLF & _
    "\\.\PHYSICALDRIVE3 Multi Flash Reader USB Device"
    $sTempFile = "temp_hdd_file.txt"
    FileDelete($sTempFile)
    FileWrite($sTempFile, $sTestData)

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

    ;- -- --- Eigentliches Skript --- -- -

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

    ;Schritt 1: Einlesen der Daten.
    ; Dies muss für alle folgenden
    ; Abfragen nur einmal erledigt
    ; werden, daher lagern wir es
    ; aus der Funktion aus, damit
    ; es wirklich nur einmal
    ; erledigt wird.
    $sHDDFileData = FileRead($sTempFile)

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

    ConsoleWrite(HDDAvailable($sHDDFileData, "\\.\PHYSICALDRIVE2") & @CRLF)

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

    Func HDDAvailable($sHDDFileData, $sHDDIdentifier)
    ;$sHDDFileData: Inhalt der HDD-Datei
    ;$sHDDIdentifier: Id der zu überprüfenden HDD
    ;Wir geben False (0) zurück, wenn die Festplatte nicht gefunden wurde
    ;Wir geben die Bezeichnung zurück, wenn die Festplatte gefunden wurde

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

    ;Schritt 2: Suchen der HDD
    ; Um die für uns interessante
    ; Zeile in der Datei zu finden,
    ; benutzen wir StringInStr.
    ; Diese Funktion gibt die Position
    ; eines Textes in einem anderen zurück.
    ; Die Rückgabe ist 0, wenn der Suchtext
    ; nicht gefunden wurde.
    $iSearchPos = StringInStr($sHDDFileData, $sHDDIdentifier)
    If $iSearchPos = 0 Then ;wenn $iSearchPos 0 ist
    Return False ;Ende! Festplatte wurde nicht gefunden
    EndIf

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

    ;Schritt 3: Bezeichnung auslesen
    ; Wir wissen, an welcher Stelle in der Datei
    ; die Festplattenbezeichnung steht, nämlich
    ; direkt nach dem Identifier und vor dem nächsten
    ; Zeilenumbruch. Dieses Wissen machen wir uns zu Nutze.
    $sDesc = StringTrimLeft($sHDDFileData, $iSearchPos)
    ; Nun haben wir alles, was nach dem Identifier kommt,
    ; bis zum Ende der Datei. Wollen wir aber nicht.
    ; Wir brauchen nur alles bis zum nächsten
    ; Zeilenumbruch. Dazu nutzen wir StringInStr...
    $iNextCRLFPos = StringInStr($sDesc, @CRLF)
    ; ... und schneiden alles rechts davon ab.
    $sDesc = StringLeft($sDesc, $iNextCRLFPos)
    ; Fast richtig. Jetzt muss nur noch der
    ; Identifier entfernt werden. Der gehört ja nicht
    ; zur Bezeichnung. Identifier ist alles, was
    ; vor dem ersten Leerzeichen steht.
    $iNextSpacePos = StringInStr($sDesc, " ")
    $sDesc = StringTrimLeft($sDesc, $iNextSpacePos)
    ; Und fertig. Übrig bleibt unsere Beschreibung.

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

    Return $sDesc
    EndFunc

    [/autoit]


    Da du ja nach einem effizienten Weg gesucht hast, hier nochmal kurz eine unverständlichere Variante der o.g. Funktion:

    [autoit]


    Func HDDAvailable($sHDDFileData, $sHDDIdentifier)
    $aTemp = StringRegExp($sHDDFileData, "(?i)\Q" & $sHDDIdentifier & "\E (.+?)\r", 3)
    Return IsArray($aTemp) ? $aTemp[0] : False
    EndFunc

    [/autoit]


    Macht exakt dasselbe, kannst du aber ignorieren, wenn du nicht auf Performance (bzw. extrem kurzen Code) angewiesen bist.

    Diese HDDAvailable-Funktion (egal welche) würde man üblicherweise in einer Schleife aufrufen. For bietet sich hier an.

    Auch, wenn das jetzt erschlagend wirkt... Nimm dir mal die Zeit und geh' die Logik komplett durch. Im Zweifelsfall kannst du auch sehr gut mit der Hilfe zu AutoIt arbeiten oder nochmal hier nachfragen.

  • Guten Abend zusammen :)

    Erstmal vielen Dank an chesstiger für deine tolle Hilfe und tolle Erklärung ^^


    Zitat von chesstiger

    Nimm's mir nicht übel, aber das liest sich grausam.


    Awa, ich weiß selber das des grausam geschrieben ist :D , aber es hat funktioniert ;)

    Heute habe ich mir endlich mal die Zeit genommen um mir deinen Code genau anzuschauen.
    Den Code habe ich jetzt einige male durchgelesen und auch zum größten teil verstanden. Habe damit auch etwas rum gespielt und ausprobiert.
    Das Funktioniert genau so wie ich das machen wollte ^^

    Könntest du mir bitte noch kurz erklären was der Befehl genau macht

    AutoIt
    ConsoleWrite(HDDAvailable($sHDDFileData, "\\.\PHYSICALDRIVE2") & @CRLF)


    So wie ich das verstanden habe startet er die Funktion HDDAvailable und übergibt die Daten der Datei in der gesucht werden soll mit dem Suchtext. Was aber bedeutet das & @CRLF) hinten dran?
    Wie muss ich diese Funktion nutzen damit ich auch nach Bezeichnungen suchen kann die Leerzeichen enthalten wie z.b Partition 1?

    Ich habe es auch hinbekommen das ich die Ergebnisse nach jedem Durchgang in eine Separate Variable geschrieben bekomme :)
    Das brauche ich, damit ich Sie mir nachher alle in einer GUI anzeigen lassen kann.

    Grüße

    Blue-Twoo

  • Zitat von Blue-Twoo

    So wie ich das verstanden habe startet er die Funktion HDDAvailable und übergibt die Daten der Datei in der gesucht werden soll mit dem Suchtext.

    Fast richtig: Er ruft die Funktion ConsoleWrite auf, die etwas unten in die Console von ScITE schreibt. Dieser Funktion übergibt er den Rückgabewert der Funktion HDDAvailable mit den von dir beschriebenen Übergabeparametern, an den noch das Makro "@CRLF" angehängt wird. Das bedeutet - deine nächste Frage fragt ja exakt dies:

    Zitat von Blue-Twoo

    Was aber bedeutet das & @CRLF) hinten dran?

    Das Makro "@CRLF" gibt die Steuerzeichen CR (Carriage Return) und LF (Line Feed) zurück, die für einen Zeilenumbruch sorgen.

    Zitat von Blue-Twoo

    Wie muss ich diese Funktion nutzen damit ich auch nach Bezeichnungen suchen kann die Leerzeichen enthalten wie z.b Partition 1?

    Du könntest die Funktion folgendermaßen umformulieren (siehe Schritt 2.1 und Zeilen 80-82):

    Es gibt Tage, da trete ich nicht ins Fettnäpfchen. Ich falle in die Friteuse.

  • Oder einfach mit regex. Aber ich gebe zu das bedar der Einarbeitung. Kann folgende Seite empfehlen:


    https://regex101.com/
    http://www.regexe.de/
    und natürlich die toDos aus dem Forum


    Gruß

    Peter

    Hinweise auf Suchmaschinen finde ich überflüssig - wer fragt hat es nicht gefunden oder nicht verstanden. Die Antwort gibt sich oftmals schneller als der Hinweis auf Dr. Goggle & Co.

    Ab 19-10-22 ergänzt um:

    Die Welt wird nicht bedroht von den Menschen, die böse sind, sondern von denen, die das Böse zulassen. (Albert Einstein)