Seite 1 von 1
Datei einlesen
Verfasst: 22. November 2011, 16:38
von psp
Ich habe eine kleine Funktion selbst geschrieben, die eine Datei einlesen soll und zeilenweise in ein Array speichern soll. Das tut es nicht
Die Datei ist eine einfache per CR+LF pro Zeile getrennte Auslistung von Nummern. Ich habe probehalber noch die Funktion FReadline und FLoadText verwendet.
Das Ergebnis der unten stehenden Funktion ist bei den Log2File-Einträgen:
1. NULL
2. NULL
3. Inhalt der Datei
Code: Alles auswählen
PROCEDURE File2Array(aArray is array of strings, cDatei is string)
resopen is int
resopen = fOpen(cDatei,foReadWrite)
IF resopen=-1 THEN
RESULT aArray
END
fSeek(resopen,1,fpBeginning)
IF resopen <> -1 THEN
ngelesen is int
ngelesen = 1
cPuffer is string
cPuffer = " "
cSatz is string
cSatz = ""
WHILE ngelesen=1
cPuffer = fRead(resopen, 1)
ngelesen = Length(cPuffer)
Log2File(cPuffer,cOutput)
IF cPuffer=CR THEN
ArrayAdd(aArray,cSatz)
cSatz=""
ELSE
IF cPuffer<>Charact(10) THEN
cSatz = cSatz+cPuffer
END
END
IF cPuffer=EOT THEN
ArrayAdd(aArray,cSatz)
//fClose(resopen)
//result aArray
END
END
END
fSeek(resopen,1,fpBeginning)
cPuffer = fReadLine(resopen)
Log2File(cPuffer,cOutput)
fClose(resopen)
cPuffer = fLoadText(cDatei)
Log2File(cPuffer,cOutput)
RESULT aArray
Re: Datei einlesen
Verfasst: 22. November 2011, 23:32
von klammerauf
Hallo psp,
dein Aufwand in allen Ehren. Aber es geht mit WinDev viel einfacher. Ich werd jetzt deine Funktion nicht umschreiben, aber schau dir bitte mal folgenden Code an:
Code: Alles auswählen
sAlles is string //da könntest du den ganzen Inhalt deiner Datei reinlesen
MyArray is array of strings
FOR EACH zeile in sAlles SEPARATED BY crlf
IF zeile <> ""
ArrayAddLine( MyArray, zeile )
END
END
Ich schreibe das hier gerade am Laptop ohne WinDev und frei aus dem Kopf. Kann also sein, dass hier die eine oder andere Sache noch nachgebessert werden muss. Aber so sollte das einfacher gehen.
HTH
Sebastian
Re: Datei einlesen
Verfasst: 23. November 2011, 00:11
von Lewi
Abgesehen davon, das Du mit Sebastians Ansatz eine elegante Lösung hättest, liegt die Ursache bei Deinem Code wohl darin, dass Du dass Array nicht korrekt initianlisiert hast.
aTest is array of 0 strings
Dies gibt auf jeden Fall ein Array mit der Länge 0
Ich meine gelesen zu haben, dass Arrays, bei denen die Anzahl der Elemente nicht dezidiert vorgeben wird, mit 2 Elementen vorbelegt werden.
Gruß, Olaf
Re: Datei einlesen
Verfasst: 23. November 2011, 07:34
von psp
Es geht ja nicht um das Array selbst, sondern dass FRead und FReadLine nichts als Ergebnis bringt.
Re: Datei einlesen
Verfasst: 23. November 2011, 07:46
von Herbert
Sebastians Ansatz ist jedenfalls transparenter.
sonst nimm anstelle von fread besser freadline, so musst du nicht zeichenweise einlesen.
Re: Datei einlesen
Verfasst: 23. November 2011, 07:56
von psp
FReadLine bringt auch leider eine leere Antwort, der weiß nicht mal, dass ein CR+LF am Ende jeder Zeile steht.
Weil ich mit diesem Problem konfrontiert wurde, hatte ich die Funktion überhaupt erstellt. Das Einzige, bei dem ich ein verwertbares Ergebnis bekomme, ist leider FLoadText. Als Programmiersprache darf es solche Fehler nicht geben. Unter WinDev selbst habe ich noch keine Datei einlesen müssen, sonst wäre mir das vielleicht als substanzieller Fehler aufgefallen.
Re: Datei einlesen
Verfasst: 23. November 2011, 09:27
von klammerauf
Guten Morgen,
psp hat geschrieben:Als Programmiersprache darf es solche Fehler nicht geben.
Ich bin im Laufe der Jahre vorsichtig geworden mit solchen Aussagen.
die erste Position in einem File ist 0 und nicht 1!!!
Du liest ein Byte ein, CR ist aber Charact(13)+Charact(10) und somit 2 Bytes!
Ich vermute, du hast deswegen kein Ergebnis gesehen, weil du erst bei Charact(10) abbrichst und somit am Ende von cSatz noch ein Charact(13) steht.
HTH
Sebastian
Re: Datei einlesen
Verfasst: 23. November 2011, 09:53
von psp
Das FSeek wurde schon mit 0 als zweiten Parameter gesetzt mit dem gleichen Ergebnis.
Das allererste Zeichen in der Datei ist definitv eine "0", aber FRead konnte dies nicht einlesen. Das zweite Zeichen, was mit FSeek gesetzt wurde ist eine "2".
In WinDev wird CR und CRLF voneinander unterschieden, CR ist sehr wohl ein einzelnes Zeichen, das ist in Xbase++ schon so. Das LF würde in die nächste einzulesende Zeile wandern. Das war mir in den Beispiel sowieso egal. In der Unix/Linux-Umgebung wird der Zeilenumbruch im Regelfall nur mit dem CR erreicht, damit kann Windows wegen dem fehlenden LF nichts anfangen. Wir arbeiten daher nur mit dem CR, ein mögliches LF wird weggefiltert.
Die erste Funktion, die ich beschrieben habe, ist die 1:1-Kopie mit kleineren Anpassungen aus Xbase++, die seit über 18 Jahren so arbeitet, damals noch mit Cli**er. Mittlerweile gibt es MemoRead um Dateien komplett einzulesen, aber das befreit einem trotzdem nicht davon, die Sachen einzeln durchzugehen. Bei festen Satzlängen kein Problem, aber es darf nie eine variable Satzlänge da sein, das deckt die genannte Funktion ab.
Mittlerweile habe ich mir das ganze noch mal zu Gemüte geführt und gesehen, dass meine auszulesende Datei trotz allem ohne das CR auf dem WinCE-Terminal landet. Damit habe ich mit einer nun festen Satzlänge die Funktion noch einmal angepasst:
Code: Alles auswählen
PROCEDURE File2Array(aArray is array of strings, cDatei is string, nZeile is int)
cPuffer is string
sZeile is string
cPuffer = fLoadText(cDatei)
WHILE True
sZeile = cPuffer[[1 TO nZeile]]
cPuffer = cPuffer[[nZeile+1 TO ]]
ArrayAdd( aArray, sZeile )
IF Length(cPuffer)<nZeile THEN
BREAK
END
END
RESULT aArray
Damit wird nun meine Combo-Box nun mit den Daten des Arrays gefüllt. Wenn jemand FRead/FReadLine ordnungsgemäß zum Laufen bekommen hat, wäre ich über eine kurze Info dankbar.
Re: Datei einlesen
Verfasst: 24. November 2011, 12:32
von Lewi
Wenn das erste Zeichen in Deiner Datei 0D (CR) ist, dann wundert es nicht, dass das Array leere Elemente enthält. Grundsätzlich schaue ich mir Dateien fremder Systeme (wie unter Unix) zunächst per Hex-Editor an, um solche "Überraschungen" zu vermeiden.
Je nach Anwendung und Betriebssystemumgebung werden Zeilenenden bei Text-Dateien unterschiedlich gehandhabt. Bei manchen wird als Zeilenende ein CRLF gesetzt, Notepad und Windows-Programme sehen in der Regel ein CR vor. Aber auch bei Windows-Programmen gibt es keine Regel ohne Ausnahme. Ich habe schon gesehen, dass ein LF für automatische Zeilenümbrüche am Zeilenende eingefügt wird.
In Verbindung mit Unix Systemen kommt es auch darauf an, unter welchen Zeichensatz die Datei generiert wurde. Im EBCDIC-Code entspricht CR ein Charact(13), ein LF entspricht Charact(37) bzw. Charact(21)
Ich arbeite mit nachfolgender Funktion zum Einlesen von ASCII-Datein in ein Array:
Code: Alles auswählen
FUNCTION fReadToArray( cFile is string , Local bShowErrorMess is boolean = true, Local bNoEmptyLines is boolean = true, Local bTrimLine is boolean = true )
aResult is array of 0 strings
sContent is string
sRow is string
If NOT fFileExist( sFile )
IF bShowErrorMess = false THEN RESULT aResult
Info("Fehler: Die Datei: " + sFile + " wurde nicht gefunden!")
RESULT aResult
END
sContent = Replace( fLoadText( cFile ), Charact(10), "") // Lese Datei und setzte alle LF auf ""
FOR EACH STRING sRow OF sContent SEPARATED BY CR
IF bNoEmptyLines = true AND NoSpace(sRow) = "" THEN CONTINUE
IF bTrimLine = true THEN sRow=NoSpace( sRow )
ArrayAdd( aResult, sRow )
NEXT
RESULT aResult
Gruß, Olaf
Re: Datei einlesen
Verfasst: 25. November 2011, 13:52
von psp
Danke für deine Antwort, mit "0" war das Ascii-Zeichen 48 gemeint, das konnte ich mit dem Multiedit nachprüfen.
Dass du auch mit fLoadText arbeitest sehe ich auch in der Funktion, wenn man mit den ganzen Widrigkeiten umgehen kann. Aber mit fRead(Line) habe ich bei den wenigen Mitlesern keine positive Bestätigung für die Funktionsweise bekommen. Werde die Tage mal mit WinDev unter Windows mal die Funktion prüfen, wenn ich etwas Zeit dafür übrig habe.
Re: Datei einlesen
Verfasst: 25. November 2011, 14:49
von BRANDELH
Hi,
mit dieser Kombination lese ich auf z.B. einem HTC Touch Diamond um die 2000 Datensätze auf einen Rutsch in ein 2 dimensionales Array:
Code: Alles auswählen
CSV_Daten is array of 1 by 2 string
...
sCSV_Data = fLoadText(gsDir_CSV+"XXX.CSV") // komplett einlesen
CSVToArray(sCSV_Data,CSV_Daten,";")
nFeldAnz = ArrayInfo(CSV_Daten,tiNumberColumns)
...
allerdings dauert es einige (wenige) Sekunden bei 1000 Sätzen.
Nun habe ich aber zusätzlich noch Dateien die deutlich größer sind und da gibt es aus meiner Sicht zwei potentielle Probleme:
1. Es dauert so lange, dass der Anwender denkt es hätte sich aufgehängt (dazwischen keine Statusmeldung möglich).
2. Irgendwann ist der Speicher voll, das kann nicht sinnvoll sein.
Daher nutze ich bei den großen Dateien die fReadString Methode:
Code: Alles auswählen
nH = fOpen(gsDir_CSV+"YYY.CSV",foRead)
IF nH = -1 THEN
Error("Die CSV Datei yyy konnte nicht geöffnet werden..")
RESULT False
ELSE
// nun den Satzaufbau prüfen, Erste Zeile einlesen !
sCSV_Data = fReadLine(nH)
IF sCSV_Data = EOT THEN
Error("Die CSV Datei yyy enthält keine Daten.")
RESULT False
END
StringToArray(sCSV_Data,CSV_Daten, ";" ) // nur noch eine Dimension !
nFeldAnz = ArrayInfo(CSV_Daten, tiNumberRows )
sError = "Die Struktur der CSV Datei yyy stimmt nicht !" // wegen der CASE ERROR etc. werden alle Fehler nach unten geleitet
// zuerst die Struktur prüfen !!!
IF Upper(CSV_Daten[ 1,1])="Feld1" AND Upper(CSV_Daten[ 2,1])="Feld2" AND ... THEN
// OK, die Struktur stimmt
ELSE
Error("Die Struktur der CSV Datei yyy stimmt nicht !")
RESULT False
END
sCSV_Data = fReadLine(nH) // das Array bleibt zweidimensional !
WHILE sCSV_Data <> EOT
// ok, prüfen und verarbeiten
...
// nächste Zeile lesen, bis zum Ende
sCSV_Data = fReadLine(nH)
END
fClose(nH)
END
allerdings kann es bei 7500 Datensätzen schon mal 10 Minuten dauern bis die Daten eingelesen und in HyperFileSQL gespeichert sind.
Billigere kleinere Windows Mobile Phones ging auch schon die Puste aus ;-)
Wenn ich die gleichen Dateien auf meinem Samsung Galaxy Plus mit der Basic4Android Version des Programmes einlese braucht das 80 Sekunden.
Die Hardware ist deutlich schneller ...
Re: Datei einlesen
Verfasst: 28. November 2011, 08:17
von psp
Ich werde mir die Tage zum Programmieren ein Android kaufen dürfen, da stehe ich natürlich im Zwiespalt. Nehm ich ein "langsameres" Modell, dann habe ich unter Umständen den mittleren unteren Standard, den die möglichen Kunden haben (weil hier auf Masse gesetzt werden muss) und kann daraufhin auf Geschwindigkeit optimieren. Wenn ich ein schnelleres nehme wie das S2, dann kann ich unter Umständen Geschwindigkeitsprobleme nicht zweifelsfrei nachvollziehen und habe womöglich dann den Ärger mit den Kunden.
Ich selbst habe privat ein iPhone 4 und da sind die Programmierschnittstellen noch recht beschränkt, sprich XCode.
Re: Datei einlesen
Verfasst: 28. November 2011, 14:46
von Lewi
1. Es dauert so lange, dass der Anwender denkt es hätte sich aufgehängt (dazwischen keine Statusmeldung möglich).
Dazu gäbe es 2 Lösungen:
1. Die Import-Routine in Verbindung mit einem Window. Die Routine wird dann im Initalisierungsteil codiert und ausgeführt. Das ganze wird dann mit Open( "ImportiereIrgendetwas") ausgeführt und es können Statusmeldungen im Fenster ausgegeben werden.
2. Es besteht aus einem Window vom Typ "Free Window" bei dem ferner die Icons für Schließen, Minimieren etc. abgeschaltet sind. Das Window enthält dann eine oder mehrer Static-Zeilen für anzuzeigende Nachrichten. In der Import-Routine wird dann dieses Fenster wie folgt geöffnet:
...
OpenChild("WORKINGBOX", sStatusMeldung1, sStatusMeldung2)
... Führe Importroutine weiter aus
//zwischendurch evt. eine Meldung ausgeben
WORKINGBOX.STATUSMELDUNG1..Caption ="Info xy"
//Zum Schluß
Close(WORKINGBOX)
....
Viele Grüße
Olaf
Re: Datei einlesen
Verfasst: 28. November 2011, 19:55
von BRANDELH
HI,
also ich bin mit meinem Samsung Galaxy S plus sehr zufrieden. Schön flott und unter 300 Euro (meine ich).
Darunter würde ich nicht gehen auch nicht unter 480x800 Punkte, die Controls für die Finger sind größer als unter Windows Mobile ;-)
@Lewi,
ich lese wie geschrieben bei größeren Dateien weilenweise ein und gebe alle 100 Sätze eine Statusmeldung in der Listbox, das wirk ordentlich und man sieht wie er arbeitet ;-)
Re: Datei einlesen
Verfasst: 1. Dezember 2011, 15:33
von psp
Ich hab wegen der "Hänge"-Problematik mit dem Multithreading in WinDev Mobile gearbeitet. Sprich eine Statusbar initialisiert und sie in regelmäßigen Abschnitten mit Informationshäppchen gefüttert. Für den Nutzer zeigt sich, dass er hier arbeitet. Man muss halt nur in den dem Fall durch Einlesefunktion die Statusbar bedienen.