Probleme mit FileReadLine

  • Hey leute,

    ich hab so ein paar Probleme mit den Funktionen

    [autoit]

    FileReadLine()

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

    _FileCountLines()

    [/autoit]

    Also ich habe folgendes vor. Ich habe ein ganzen schwung *.txt Dateien gesammelt über die Zeit und will nun die Inhalte Zeilen weise in eine MySQL DB Übertragen. Gibt sicher einfachere möglichkeiten als groß ein skript in AutoIT schreiben. Aber ich denke, wenn man sich solche aufgaben stellt lernt man am besten mit ne für mich noch relativ neuen Programmiersprache um zu gehen. In den *.txt Dateien befinden sich Linklisten, die zum Teil mit 1 oder mehren Leerzeilen unterbrochen sind für Übersichtlichkeit.

    Nun möchte ich erst die Dateien öffnen lassen, damit über die Funktion

    [autoit]

    _FileCountLines()

    [/autoit]

    Die ganzen Zeilen gezählt werden, um so die schleife besser an zu sprechen, die diese Dateien Zeilenweise auslesen soll. Das mit den Leerzeilen rausfiltern denke ich werde ich so schon hin bekommen.

    Nur die beiden oben genannten Funktionen funktionieren nicht wirklich. Also die Funktion

    [autoit]

    _FileCountLines()

    [/autoit]

    gibt mir keine Anzahl aus und die Funktion

    [autoit]

    FileReadLine()

    [/autoit]

    liest egal bei welcher Zeile nichts aus der *.txt Datei aus.

    Die Dateien sind immer wie folgt aufgebaut:

    Link1

    Link2

    ...


    Hoffe ihr versteht was ich von euch will und Ihr könnt mir vll helfen? Wäre super.


    Michael

    Einmal editiert, zuletzt von lwl2011Bochum (20. Oktober 2011 um 19:46)

  • kannst mir vll in dem zusammenhang noch ein paar mehr information dazu? Blicke gerade nicht ganz 100 pro durch. Bin leider noch relativ bei Beginn zum lernen von AutoIT. (Ich weiß irgendwie scheiß formulierung).


    Michael

  • Mit _FileReadToArray() liest du die Datei zeilenweise in ein Array ein. Was ist ein Array? -> http://www.bug-fix.info/array_tut.htm

    Mit der For...In-Schleife verarbeitest du jedes Element im Array. Die If-Bedingung prüft nur, ob das aktuelle Element leer ist (Leerzeile). Wenn nicht, mach was mit der Textzeile.

  • und diese Funktion endet automatisch mit dem letzten element?

    oder muss ich da das mit dem zählen noch vorher hin bekommen?

    Michael

  • Da musst du nix zählen. Schau dir For ...In mal in der Hilfe an.

    Wenn du dort mal die Beschreibung zu _FileReadToArray() liest, wirst du feststellen das im ersten Arrayelement die Anzahl der Elemente abgelegt wird. Also wäre auch folgendes möglich:

    For $i = 1 To $aArray[0]

    Genausogut könntest du auch

    For $i = 1 To UBound($aArray)-1

    verwenden.

    Lies dir erstmal das Array Tutorial durch um zu verstehen, was das ist. Ein- und Zweidimensionale Arrays sollten dir für den Anfang reichen.

  • Hab nun ein Skript, was eigentlich denke ich Funktionieren könnte, für das was ich brauche. Nur leider gibt mir das blöde Ding nur nen Fehler unten beim Starten aus und keine Array Liste. Hier erstmal das Skript.

    [autoit]

    #include <array.au3>
    #include <file.au3>

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

    Dim $b, $Liste, $i, $aArray
    $b = 1

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

    _FileReadToArray("test.txt", $aArray)

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

    For $i = 1 To $aArray[0]

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

    if $aArray[$i] <> "" Then

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

    $Liste[$b] = $aArray[$i]
    $b = $b + 1

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

    EndIf

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

    Next

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

    _ArrayDisplay($Liste)

    [/autoit]

    Als Anhang packe ich mal die hier verwendete Textdatei bei, die im selben Ordner liegt wie das Skript.

    Und nun noch den Fehler:

    [autoit]


    >"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "C:\Users\Michael\Desktop\AutoIT Dateien\Tutorials\ReadLine\Liste erstellen für Links.au3" /autoit3dir "C:\Program Files (x86)\AutoIt3" /UserParams
    +>01:42:36 Starting AutoIt3Wrapper v.2.0.3.0 Environment(Language:0407 Keyboard:00000407 OS:WIN_7/ CPU:X64 OS:X64)
    >Running AU3Check (1.54.19.0) from:C:\Program Files (x86)\AutoIt3
    +>01:42:36 AU3Check ended.rc:0
    >Running:(3.3.6.1):C:\Program Files (x86)\AutoIt3\autoit3_x64.exe "C:\Users\Michael\Desktop\AutoIT Dateien\Tutorials\ReadLine\Liste erstellen für Links.au3"
    C:\Users\Michael\Desktop\AutoIT Dateien\Tutorials\ReadLine\Liste erstellen für Links.au3 (10) : ==> Subscript used with non-Array variable.:
    For $i = 1 To $aArray[0]
    For $i = 1 To $aArray^ ERROR
    ->01:42:36 AutoIT3.exe ended.rc:1
    >Exit code: 1 Time: 1.669

    [/autoit]


    Hoffe sind alle nötigen Infos damit jemand durch blickt was ich will.


    Michael

  • Hi Willkommen im Forum. Ich habs mal ausgebessert und mit Kommentaren versehen, sollte eigentlich selbsterklärend sein. Viel Erfolg ;) BTW: Es in ein Array auszulesen geht bei größeren Dateien sehr sehr sehr viel schneller als jede Zeile einzeln auszulesen!

    [autoit]


    #include <array.au3>
    #include <file.au3>

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

    Global $b = 1, $aArray
    Dim $Liste[2] ; Erstellt ein Array mit 2 Elemten ('Schubladen') Achtung: Beginnt bei 0! D.h. $liste[2] existiert beim Aufruf nicht!

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

    _FileReadToArray(@ScriptDir & "\test.txt", $aArray)

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

    ;~ If @error Then
    ;~ MsgBox(16, "@error", @error)
    ;~ EndIf
    ;~ _ArrayDisplay($aArray)
    ;~ --> Fehler gefunden: Datei falsch benannt ('text.txt.txt') & Pfad falsch angegeben

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

    For $i = 1 To $aArray[0]

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

    if $aArray[$i] <> "" Then
    ReDim $Liste[$b+1] ; Redim => Ändert die Dimension; Hier: fügt ein weiteres Element am Ende hinzu
    $Liste[$b] = $aArray[$i]
    $Liste[0] = $b ; für spätere mögliche Verwendung: Speichert die Anzahl der Elemente in Element 0
    $b += 1 ; so sparst du dir Zeichen

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

    EndIf

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

    Next

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

    _ArrayDisplay($Liste)

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

    ;Kürzer ginge es auch in dem du einfach alle Zeilen mit nichts drin löscht:

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

    For $i = $aArray[0] To 1 Step -1
    If $aArray[$i] = "" Then
    _ArrayDelete($aArray, $i)
    $aArray[0] -= 1
    EndIf
    Next
    _ArrayDisplay($aArray)

    [/autoit]
  • Danke das funktioniert endlich. und das mit dem Falsch benannte Textdatei hab ich gerad nach deinem hinweiß gesehen. irgendwie peinlich *verlegen grinsen*

    Nur so muss ich nun gucken, dass ich beide Teile verbinde. Wenn ich soweit bin Post ich mal mein fertiges skript.

    Danke bis hier her erstmal.

    Wenns Probleme gibt meld ich mich.


    Michael

  • BTW: Es in ein Array auszulesen geht bei größeren Dateien sehr sehr sehr viel schneller als jede Zeile einzeln auszulesen!

    Wenn man jede Zeile nur einmal verwenden muss (wie in seinem Fall wo er die Inhalte nur jeweils 1x in eine SQL-DB übertragen will) ist man mit FileReadLine nicht "sehr sehr sehr viel" langsamer. Im Gegenteil - bei mir sogar schneller.
    Außerdem hat man nicht die gesamte Datei im Speicher sondern jeweils immer nur 1 einzige Zeile.
    Mal als Beispiel zum nachvollziehen:
    Aufgabe: In der WinApi.au3 alle Zeilen finden in denen das Wort "AutoIt" vorkommt (die Ausgabe per ConsoleWrite wurde der Übersicht halber auskommentiert):

    'Performancevergleich _FileReadToArray() vs. FileReadLine()
    [autoit]

    #include <File.au3>

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

    Global Const $s_DateiPfad = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 2, -1)) & "Include\WinApi.au3"
    Global Const $N = 100
    Global $iT, $ix

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

    ; Mit FileReadLine überprüfen ob in einer Zeile der Datei das Wort "AutoIt" vorkommt:
    $iT = TimerInit()
    For $i = 1 To $N
    $ix = 0
    $h_File = FileOpen($s_DateiPfad, 0)
    Do
    $s_Line = FileReadLine($h_File)
    If @error = -1 Then ExitLoop
    $ix += 1
    If StringInStr($s_Line, "AutoIt") Then $ix = $ix; ConsoleWrite($ix & ", ")
    Until 0
    ; ConsoleWrite(@CRLF)
    FileClose($h_File)
    Next
    $iT = TimerDiff($iT) / $N
    ConsoleWrite("mit FileReadLine: " & Round($iT,2) & "ms" & @CRLF)

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

    ; Mit _FileReadToArray überprüfen ob in einer Zeile der Datei das Wort "AutoIt" vorkommt:
    $iT = TimerInit()
    For $i = 1 To $N
    Global $a_Array
    _FileReadToArray($s_DateiPfad, $a_Array)
    For $x = 1 To $a_Array[0]
    If StringInStr($a_Array[$x], "AutoIt") Then $x = $x ;ConsoleWrite($x & ", ")
    Next
    ; ConsoleWrite(@CRLF)
    $a_Array = 0
    Next
    $iT = TimerDiff($iT) / $N
    ConsoleWrite("mit _FileReadToArray: " & Round($iT,2) & "ms" & @CRLF)

    [/autoit]


    Ergebnis dann bei mir:

    Code
    mit FileReadLine: 56.31ms
    mit _FileReadToArray: 61.27ms


    Die Speicherschonende Variante mit FileReadLine ist nicht sehr sehr sehr viel langsamer sondern schneller.

  • ja danke für diesen vergleich, aber ich denke ich bleib bei dem einem system mit dem Array, was nun bei mir läuft. Nur nun muss ich das Skript noch ein wenig erweitern, wo alle dateien in einem verzeichnis nach und nach so ab arbeite. gibts da eine fertige Funktion bei autoit schon für oder muss man sich da selber was einfallen lassen? Also als Info, die Dateien wurden am ende lediglich duch eine fortlaufende Nummer ergänzt. Also erste Datei lautet "Neue Datei 1.txt", zweite Datei lautet "Neue Datei 2.txt" usw. bis "Neue Datei 69.txt".


    Michael

  • ich denke ich nehm die letzte Variante die sieht super aus und Funktioniert erste Klasse. Ich werd heute abend oder später mal gucken, dass ich alle Dateien zusammenbaue und dann erstmal jede Zeile der rund 70 Dateien in 1e Datei mal zusammen schreiben. Also obs Funktioniert. bevor ich es in eine MySQL Datenbank übertrage.

    Bei Problemen Poste ich wieder mal, bemühe mich es aber so hin zu bekommen.

    Michael

  • gibts evtl bei dieser Variante eine einfache Möglichkeit zu überprüfen ob ein Element bereits existiert also im Array? Weil bin mir nich sicher das immer nur alle Links 1 mal vorhanden sind? Den ich denke ich packe erst alle Inhalte der verschiedenen Dateien in einen Array und schreibe es im anschluß in eine TXT Datei.


    Michael

  • So mein Programm ist nun fertig. Also es liest erst meine Textdateien aus, packt den Inhalt in eine Temporäre Datei. Dann löscht er leer Zeilen aus dem Datenwust, sucht nach Doppelgängern und löscht diese. Und als letzten Schritt überträgt er die Fertige Daten aus der Entgültigen Datei in die MySQL Datenbank und löscht die Temporäre Datei.

    Ich werde das Skript denk ich mal die Tage mal rein packen, wenns jemand interessiert. Nur muss dort erstmal mein Skript eigene Includierte Skriptteile, damit das Hauptskript nicht so gigantisch wird, sowie Übersichtlichkeit. Darüber hinaus muss ich noch meine Verbindungsdaten für die Datenbank verpacken, schließlich brauch keiner von euch meine *fg* Ich denke ich packe die in eine Externe Ini Datei und verschlüssel diese. Den offen in INI Datei wäre auch blödsinn.

    Also wenn jemand skript ma sehen möchte, einfach kurze Meldung geben und pack die die Tage rein.


    Michael