Forum: Mikrocontroller und Digitale Elektronik ESP2866 - SPIFFS .txt letzte Zeile lesen


von Ron (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe Community,

ich versuche einen Außen-Temperatursensor mit einem EP2866 und der 
Arduino IDE zu programmieren. Im groben läuft es wie folgt ab.
      -  Temperatur Messen und Werte im 2D Array Speichern
      -  2D Array in eine .txt Datei auf dem Flash Speichern
      -  .txt Datei mittels FTP an Fritzbox senden
Soweit funktioniert das. Probleme habe ich jedoch beim auslesen der .txt 
Datei.
In der .txt steht folgender Inhalt:
    #;1;22:38:44;01;01.10;ESP2866;Fahrradschuppen;
Ich möchte gerne die am Anfang stehende laufende Nummer der letzten 
Zeile auslesen( von der .txt im flash)
Ich dachte dass ich das über die Funktion Stream.find() machen kann. 
(über .find() die Anzahl Zeilen bestimmen und dann zur letzten Zeile 
Springen) Allerdings erhalte ich immer ein false.

Einen Ansatz mit fester Zeilenbreite habe ich noch nicht verfolgt. Würde 
es gerne so versuchen.

Ich hoffe es kann mir jemand einen Denkanstoß geben wie ich eine .txt im 
Flash an bestimmten Stellen lesen kann.

Mein Beipielcode:
1
#include "FS.h"
2
3
void setup() {
4
  Serial.begin(9600); 
5
  delay(1000);
6
  
7
  SPIFFS.begin();
8
  File f = SPIFFS.open( "/FTP-Daten/test.txt", "r"); // Datei zum lesen öffnen
9
  if (!f) {
10
    Serial.println("file open failed");
11
  }
12
  String data = f.readString();                      // Inhalt der Textdatei wird gelesen...
13
  Serial.println("Inhalt der geöffneten Datei:");
14
  Serial.println(data);                              // ... und wieder ausgegeben
15
16
17
  f.seek(0,SeekSet);                                 // verschiebt den Cursor vom anfang
18
  
19
  char  Such        = 35;                            // 35 = #
20
  float Groesse     = f.size();                      // größe der Datei in bytes wird ausgelesen
21
  float Position    = f.position();                  // Aktuelle Position des Cursors in Byte
22
23
  int Anzahl        = 0;
24
  bool Gefunden     = 0;
25
  do{
26
      Serial.print("Schleifennr.");
27
      Serial.println(Anzahl);
28
      Gefunden = f.find(Such);
29
      Anzahl++;
30
  }while (Gefunden = false);
31
32
   Serial.println(Anzahl);
33
   Serial.println(Such);
34
   Serial.println(Gefunden);
35
36
  Serial.println(Groesse);
37
  Serial.println(Position);
38
 
39
  f.close();
40
}
41
void loop() {
42
43
  delay(1000);
44
}

von Matthias L. (lindner8712)


Lesenswert?

Hi,
wie wäre es denn mit:
1
String data="";
2
    while(file.available()) { 
3
        data= file.readStringUntil('\n');
4
    }
somit hast schonmal die letzte Zeile in einer Variablen.
Nur noch zerlegen:
1
NummerMax=split(data,';',2);2ten teil des Strings lesen
2
 
3
String split(String s, char parser, int index) {
4
  String rs="";
5
  int parserIndex = index;
6
  int parserCnt=0;
7
  int rFromIndex=0, rToIndex=-1;
8
  while (index >= parserCnt) {
9
    rFromIndex = rToIndex+1;
10
    rToIndex = s.indexOf(parser,rFromIndex);
11
    if (index == parserCnt) {
12
      if (rToIndex == 0 || rToIndex == -1) return "";
13
      return s.substring(rFromIndex,rToIndex);
14
    } else parserCnt++;
15
  }
16
  return rs;
17
}

Die Methode ansich ist aber ziemlich unschön.
je mehr Daten du wegspeicherst desto länger dauert die Suche weil 
jedesmal
die gesamte Datei durchgenudelt werden muss...
Evtl die letzte Nummer in einer Datei oder EEPROM zu speichern
und die dann bei Bedarf auslesen?


Gruß

von Ron (Gast)


Lesenswert?

Guten Abend,
vielen Dank für die schnelle Antwort und den Beispielcode 💐. Ich habe 
die letzten Abende damit verbracht die Logik dahinter zu verstehen und 
auf dieser Basis selber diese Funktion zu programmieren.
Soweit klappt alles.

Dass diese Methode unschön ist habe ich schon häufig gelesen. Ich konnte 
es aber noch nicht nachvollziehen warum (Blockierungsfreie 
Programmierung). In meinen Fall ist die Datei nach 3 Monaten 426Kb groß. 
Wird die Datei komplett durchsucht dauert das etwa 20s. Nun Springe ich 
mit
1
f.seek(100,SeekEnd);
bis kurz vor das Ende. Somit dauert die Suche nur noch 1s. Das sollte 
doch keine Probleme machen.

Die letzte Nummer im EEPROM zu Speichern wäre wohl die einfachste 
Variante gewesen das Problem zu lösen. Diese Methode kannte ich aber 
schon und ich wollte etwas Neues ausprobieren.

Vielen Dank nochmal und für Interessierte hier meine Variante um aus 
einer im Flash liegenden .txt Datei, Daten aus der letzten Zeile 
wiederzugeben.

MFG: Ron
1
#include "FS.h"
2
3
void setup() {
4
  Serial.begin(9600); 
5
  delay(1000);
6
7
  String Spalte2 = _WertAusLetzteZeile (2,';');    // (Spalte,Trennzeichen) 
8
  Serial.print("Wert aus Spalte 2: ");
9
  Serial.println(Spalte2);
10
}
11
void loop() {
12
13
  delay(1000);
14
}
15
16
String _WertAusLetzteZeile (int Spalte, char Trennzeichen){
17
18
  SPIFFS.begin();
19
  File f = SPIFFS.open( "/FTP-Daten/test_30Tage.txt", "r");                   // Datei zum lesen öffnen
20
  if (!f) {
21
    Serial.println("file open failed");
22
  }
23
//String data = f.readString();                                               // Inhalt der gesamten Textdatei wird gelesen...
24
//Serial.println("Inhalt der geöffneten Datei:");
25
//Serial.println(data);                                                       // ... und wieder ausgegeben
26
  Serial.println();
27
28
// **** Letzte Zeile aus der im SPIFFS abgelegten .txt Datei suchen ***********************************************************
29
30
                // es wird bis kurz vor das ende gesprungen damit das suchen der Letztn Zeile nicht so lange dauert
31
  if (f.size() > 200){                                          // wenn die Datei größer 200byte ist wird gesprungen
32
//   f.seek(100,SeekSet);                                       // SeekSet -> Position wird auf "offset" Bytes vom Anfang gesetzt
33
//   f.seek(100,SeekCur);                                       // SeekCur -> aktuelle Position wird um "offset" Bytes verschoben
34
     f.seek(100,SeekEnd);                                       // SeekEnd -> Position wird auf "offset" Bytes vom Ende der Datei desetzt
35
//   Serial.println(f.position());                              // Aktuelle Position bestimmen
36
  }                            
37
38
  String Zeile = "";
39
    while (f.available()){                                    // so lange noch daten kommen ist die Schleife aktiv
40
        Zeile = f.readStringUntil('\n');                      // es wird bis zum Zeilenende (\n) alles ausgelesen
41
    }                                                         // nach der letzten zeile wird die Schleife beendet
42
    
43
  Serial.println("inhalt der letzten Zeile");
44
  Serial.println(Zeile);                                      // die zuletzt gestreamte Zeile ist im String gespeichert
45
46
// *** Hier wird eine bestimmte Spalte aus der letzten Zeile extrahiert
47
48
  int StartPunkt    =0;                                       // Startposition der Spalte
49
  int EndPunkt      =0;                                       // Endposition der Spalte
50
51
  for(int i=0; i<Spalte; i++){
52
    
53
    if (EndPunkt+1 == Zeile.length()) return "angegebene Spaltenanzahl zu hoch";
54
    if(!i==0) StartPunkt = EndPunkt + 1;                      // für die erste Spalte ist der Startpunkt 0
55
    EndPunkt = Zeile.indexOf(Trennzeichen,StartPunkt + 1);    // es wird der nächste trennzeichen gesuch die suche beginnt beim letzten
56
    if (EndPunkt == -1) return "Trennzeichen nicht vorhanden";
57
    }
58
  String SpalteX = Zeile.substring(StartPunkt,EndPunkt);      // der String vom Startpunkt (inklusive) bis zum Endpunkt (exklusive) extrahiert
59
 
60
  f.close();
61
62
  return SpalteX;
63
}

von Matthias L. (lindner8712)


Lesenswert?

Hallo,

Sieht doch gut aus,
Persönlich find ich den Ansatz einfach vom Ende weg mit Offset zu suchen 
richtig gut.

Die ursprüngliche Methode war eben deswegen unschön da die gesamte Datei 
gelesen werden muss um das Ende bzw. Letzte Zeile zu erreichen.

Das hast aber mit f. Seek schön umgangen :-)

Zum Thema blockierungsfrei: ich denke du sprichst hier von yield(), 
delay() und Wdt_feed(). Die geben aber nur der CPU Zeit ihre eigenen 
Protokolle abzuarbeiten.

Grüße

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.