Hallo,
ich möchte aus einer Textdatei Zeile für Zeile auslesen und mit einem vogegeben Wert code und datum vergleichen. Das klappt ganz gut, da ich einfach einen couter i nach jeder ausgelesenen Zeile hochzählen lasse und wenn er bei 20 ist, bricht er die schleife ab.
Das Problem ist, dass ich es nicht schaffe, dass er am ende der Datei selbst aufhört. Da ich irgendwann mehr als 20 Einträge habe findet wer dann die letzten nicht mehr. Stelle ich den Schleifenabbruch i auf 1000, dauert es jedesmal ewig....
Wie kann ich die Schleife abbrechen wenn er am Ende der Datei ist?
in der Datei time.csv steht:
// Datum;code;kommen;Uhrzeit
31.03.16;2485790;KOMMEN;16:07
31.03.16;2501230;KOMMEN;16:23
///// Datei früher für eine andere Operation schon mal initialisert und wieder geschlossen
...
SdFile daten("time.csv", O_APPEND | O_WRITE);
...
daten.close();
...
///// Datei für Verleich neu geöffnet
daten.open("time.csv", O_READ); //**************************************************
char line[60];
int i = 0;
int c;
uint32_t pos;
char* datum = date;
char* zeit = time;
int gefunden = 0;
daten.rewind();
while (1) {
pos = daten.curPosition();
if (daten.fgets(line, sizeof(line)) < 0) {
Serial.println("Line not found");
}
char cp[8];
char dat[8];
sprintf(cp,"%ld",code);
Serial.print("i = ");
Serial.print(i);
Serial.print(" / ");
Serial.write("**Line: ");
Serial.print(line);
Serial.print(" / ");
if (strstr(line,datum) && strstr(line,cp))
{
Serial.print("**Datum vorhanden: ");
Serial.print(datum);
Serial.print(" / ");
Serial.print("**Code auch voranden: ");
Serial.print(line);
Serial.print(cp);
Serial.print("------Alles OK----- ");
gefunden = 1;
break;
}
if (strstr(line,datum) && !strstr(line,cp))
{
Serial.print(">> Nur Datum in Time.csv vorhanden: ");
Serial.print(line);
Serial.print(" / ");
Serial.print(datum);
}
if (!strstr(line,datum) && !strstr(line,cp))
{
Serial.print(">> Weder Datum noch code vorhanden: ");
Serial.print(line);
Serial.print(" / ");
Serial.print(datum);
}
i++;
if (i>=20) break;
Serial.print(" / Ende");
Serial.println();
}
daten.close();
Guckst du fgets
If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof)
Oder du nimmst das primitive fgetc, und prüfst jedes Zeichen auf Zeilenende/ Dateiende
sdFat hat da eine schöne Methode dafür in der File Klasse. fgets()
int16_t SdBaseFile::fgets
( char * str,
int16_t num,
char * delim = 0
)
Get a string from a file.
fgets() reads bytes from a file into the array pointed to by str, until num - 1 bytes are read, or a delimiter is read and transferred to str, or end-of-file is encountered. The string is then terminated with a null byte.
fgets() deletes CR, '\r', from the string. This insures only a '\n' terminates the string for Windows text files which use CRLF for newline.
Parameters
[out] str Pointer to the array where the string is stored.
[in] num Maximum number of characters to be read (including the final null byte). Usually the length of the array str is used.
[in] delim Optional set of delimiters. The default is "\n".
Returns
For success fgets() returns the length of the string in str. If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
Liest eine Zeile in ein Array und liefert 0 wenn das Ende da ist
Es ist aber kein Problem das per Hand zu implementieren. Dann kann man die gleiche Funktion verwenden um von Serial zu lesen!
Danke für die Antwort.
Wie kann ich das per Hand implementieren?
Indem du auf das Ende abfragst. Lies dir doch die Doku durch! Die ist doch bei SdFat super
int16_t SdBaseFile::read ()
Read the next byte from a file.
Returns
For success read returns the next byte in the file as an int. If an error occurs or end of file is reached -1 is returned.
Das mit while(1) solltest du übrigens wegelassen. Mache das Auslesen der Zeile in einer while-Schleife solange die Länge > 0 ist. Und wenn du einen gewünschsten String hast machst du break.
Ok habs gelöst.
read kannte ich schon.
Das Problem mit read() war, das mit dann immer von der nächsten Zeile das 1. Zeichen gefehlt hat.
Mit dem Setzen der Position um eins zurück war es dann kain Problem mehr.
c = daten.read();
pos = daten.curPosition();
daten.seekSet(pos-1);
if ( c < 0) break;
Danke.
Scheint aber auch mehr auf einen falschen Algorithmus hinzudeuten. Zeilen werden mit einem CR + LF abgeschlossen. Man liest also alle Zeichen größer gleich 32/0x20 (das Leerzeichen) in das Array. Bei allen anderen Zeichen vergleicht man ob man man entweder -1 oder das LF hat. Im ersten Fall ist die Datei zu Ende. Im zweiten die Zeile.
Ich weiss dass die Zeilen mit CR + LF abgeschlossen werden.
Ich hab jetzt mal etwas rumexperimentiert und eine gut funktionierende Lösung gefunden.
habs jetzt so gelöst. Funzt einwandfrei....
SdFile daten("time.csv", O_READ);
while ((c = daten.read()) >= 0)
{
pos = daten.curPosition();
daten.seekSet(pos-1);
if (daten.fgets(line, sizeof(line)) < 0) {
Serial.print("Line not found");
}
Serial.print("Testausgabe");
Serial.print(line);
}
Danke nochmal...
Bessere Variante:
daten.open("time.csv", O_RDWR);
while (daten.available ())
{
if (daten.fgets(line, sizeof(line)) < 0) {
Serial.print("Line not found");
}
Serial.print("Testausgabe2 ");
Serial.print(line);
}
daten.close();
Funzt super, dass ich da nicht gleich draufgekommen bin (HANDAUFGESICHTKLATSCH)
DANKE.....
Manchmal sind die einfachsten eben doch die besten Methoden.....
pos = daten.curPosition();
daten.seekSet(pos-1);
Das ist ein Hack. Keine Lösung
Der Grund weshalb du das "brauchst" ist ganz simpel. Mit read() liest du ein Zeichen und der Datei-Zeiger wird inkrementiert. Das willst du hier aber nicht. Wenn du dir ein Zeichen nur anschauen willst, ohne den Zeiger zu inkrementieren musst du peek() verwenden