Datei einlesen

Hier sollten nur Windev MOBILE speziefische Infos stehen, der Rest kommt ins normale Windev Forum.
Antworten
psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Datei einlesen

Beitrag 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

Benutzeravatar
klammerauf
Member
Beiträge: 116
Registriert: 28. November 2010, 15:11
Wohnort: bei Karlsruhe
Kontaktdaten:

Re: Datei einlesen

Beitrag 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
--
WinDev 23, WM Apps für Android und iOS, Anwendungen für Windows CE Mobile Barcode Scanner, Python 3 mit Oracle

Lewi
Member
Beiträge: 74
Registriert: 3. September 2010, 14:45
Wohnort: Hamburg
Kontaktdaten:

Re: Datei einlesen

Beitrag 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

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag von psp »

Es geht ja nicht um das Array selbst, sondern dass FRead und FReadLine nichts als Ergebnis bringt.

Herbert
Site Admin
Beiträge: 529
Registriert: 23. Februar 2010, 08:06
Wohnort: Langenthal, Schweiz
Kontaktdaten:

Re: Datei einlesen

Beitrag von Herbert »

Sebastians Ansatz ist jedenfalls transparenter.

sonst nimm anstelle von fread besser freadline, so musst du nicht zeichenweise einlesen.

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Benutzeravatar
klammerauf
Member
Beiträge: 116
Registriert: 28. November 2010, 15:11
Wohnort: bei Karlsruhe
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Code: Alles auswählen

fSeek(resopen,1,fpBeginning)  
die erste Position in einem File ist 0 und nicht 1!!!

Code: Alles auswählen

cPuffer = fRead(resopen, 1)
...
IF cPuffer=CR THEN
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
--
WinDev 23, WM Apps für Android und iOS, Anwendungen für Windows CE Mobile Barcode Scanner, Python 3 mit Oracle

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Lewi
Member
Beiträge: 74
Registriert: 3. September 2010, 14:45
Wohnort: Hamburg
Kontaktdaten:

Re: Datei einlesen

Beitrag 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

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Benutzeravatar
BRANDELH
Site Admin
Beiträge: 199
Registriert: 30. Juni 2010, 14:31
Wohnort: Germersheim
Kontaktdaten:

Re: Datei einlesen

Beitrag 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 ...

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Lewi
Member
Beiträge: 74
Registriert: 3. September 2010, 14:45
Wohnort: Hamburg
Kontaktdaten:

Re: Datei einlesen

Beitrag 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

Benutzeravatar
BRANDELH
Site Admin
Beiträge: 199
Registriert: 30. Juni 2010, 14:31
Wohnort: Germersheim
Kontaktdaten:

Re: Datei einlesen

Beitrag 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 ;-)

psp
Junior Member
Beiträge: 32
Registriert: 8. September 2010, 09:28
Kontaktdaten:

Re: Datei einlesen

Beitrag 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.

Antworten