Cependant, la taille totale du fichier ne tombe pas rond, par exemple 29900 octets pour 365 jours.
pour info, ces fichiers sont créés en Python avec ce script. Soyez indulgents pour le bricolage du code, je connais pas Python et ephem ne semble retourner de datetime.
Qui soit, ce n'est pas le domaine ici et j'ai donc créé exprès un petit fichier txt tout propre, avec les même lignes que ci-dessus: 79 caractères plus un retour à la ligne, soit 240 octets pour 3 lignes.
Voici le code le lecture :
#include <SPI.h>
#include <SD.h>
File myFile;
char buff[80]; // 79 + \n
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
if (SD.exists("2022.txt")) {
Serial.println("2022.txt exists.");
} else {
Serial.println("2022.txt doesn't exist.");
}
myFile = SD.open("2022.txt", "r");
//Serial.println(myFile.read(&buff,80));
myFile.read(buff, 80);
Serial.println(buff);
myFile.close();
}
void loop() { }
Cette ligne lit le texte + le \n. Pas de chance, il va manquer le terminateur de chaine \0.
Ne pas oublier que les C-string doivent se terminer par \0. Sinon le print que tu fais derrière va lire la mémoire jusqu'à trouver un 0 et accessoirement se planter.
Bonjour,
pas de bonnes nouvelles.
J'ai modifié le script Python en ajoutant \0 derrière le \n pour terminer la ligne myFile.write(sdt+"\n\0")
Un fichier de 365 jours fait 29.565 octets, soit tout pile des lignes de 81 octets. Du coup, j'ai utilisé un éditeur hexadécimal et je vois que toutes les lignes se terminent par 0d 0a 00. Je ne pensais pas que le '\n' générait le CR et le LF...
J'ai donc supprimé le \n et le fichier de 365 jours fait maintenant 28.835 octets, soit des lignes de 79 octets. Bien entendu la lecture humaine est moins simple, mais ce n'est pas l'objectif.
Ce n'est pas du tout ce dont parlait fdufnews
Il ne sert à rien d'ajouter ce '\0'.
Le fichier doit être lu jusqu'à rencontrer '\n', en éliminant les '\r'.
Ensuite un '\0' doit être ajouté en fin de chaîne.
Tu peux t'inspirer de ce qui est fait dans la librairie SDFat :
Voir la fonction : int FatFile::fgets(char* str, int num, char* delim)
Autrement, si tu utilisais la librairie SDFat au lieu de SD ?
myFile = SD.open("2022.txt"); // à noter et important : sans mode 'r' !
sBuff = "";
for (int i = 0; i < 79; i++) { // \0 y compris dans ce cas-ci !
sBuff += (char)myFile.read();
}
Serial.println(sBuff);
myFile.close();
J'ai compris pour le \0, je dois l'ajouter en fin de chaine. Je l'avais appris, mais oublié.
Je l'ai essayé et il ne fonctionne pas.
Je peux reprendre mon ancien format de fichier (\n) pour le rendre + humain, calculer le seek et ce sera bon.
Là, j'ai un objet String que je peux manipuler facilement, tout baigne
Sauf que tu risques la fragmentation mémoire, surtout si tu utilise d'autres String par ailleurs.
Je te conseille de réserver un espace pour ta chaîne. sBuff.reserve(80);
Je ne connaissais pas cette méthode. Merci. (mais elle ne fonctionne pas)
À titre d'information, j'ai décidé de mettre le null dans le fichier suivi du \n pour sa lisibilité.
En incluant le null dans le fichier, il est "naturellement" ajouté à la String lors de la lecture, et cela ne mange pas de pain.
Alors voilà le croquis de lecture de ces éphémérides. Va s'y ajouter des affichages sur une matrice LED de 12 éléments, ou, dans un autre projet, commander l'ouverture/fermeture d'une porte de poulailler (aube et nuit)
Mais d'abord le résultat pour ce 9 janvier 2022 (en UTC 0) : 09/01/2022;Aube : 07:06:23;Lever : 07:45:13;Coucher : 16:02:17;Nuit : 16:41:07
Le croquis
#include <SPI.h>
#include <SD.h>
#include <Wire.h> //include Wire.h library
// RTC
#include <TimeLib.h>
#include <DS1307RTC.h>
tmElements_t tm;
File myFile;
byte mDay = 0;
int nrJ = 0;
String sBuff;
//sBuff.reserve(80);
unsigned long long secondeMillis = 0 ;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
delay(50);
Serial.print("Initialisation carte SD ...");
if (!SD.begin(4)) {
Serial.println("Initialisation en défaut!");
} else {
Serial.println("Initialisation OK.");
}
secondeMillis = superMillis(); // top départ
}
void loop() {
if (superMillis() >= secondeMillis)
{ // nouvelle seconde
secondeMillis += 1000; // pour seconde suivante
RTC.read(tm); // lecture horloge
if (mDay != (tm.Day)) { // nouveau jour
mDay = tm.Day;
String fileName;
int mYear = tmYearToCalendar(tm.Year);
fileName = String(mYear) + ".txt";
nbrJoursAnnee();
myFile = SD.open(fileName); // sans le mode 'r'
if (myFile) {
/*
une ligne fait 78 caractères utiles + NULL et + 2 à cause du '\n' (CR et LF) qui ne servent qu'à rendre le fichier "humain"
Lire les 79 caractères, null ('\0') compris
*/
myFile.seek(81 * (nrJ - 1) ); // positionnement à partir de 0
sBuff = "";
for (int i = 0; i < 79; i++) {
sBuff += (char)myFile.read();
}
Serial.println(sBuff);
} else {
Serial.println("error opening " + fileName );
}
}
}
}
void nbrJoursAnnee() {
nrJ = 0;
switch (tm.Month)
{
case 2 : nrJ = 31; break;
case 3 : nrJ = 59; break;
case 4 : nrJ = 90; break;
case 5 : nrJ = 120; break;
case 6 : nrJ = 151; break;
case 7 : nrJ = 181; break;
case 8 : nrJ = 212; break;
case 9 : nrJ = 243; break;
case 10 : nrJ = 273; break;
case 11 : nrJ = 304; break;
case 12 : nrJ = 334; break;
}
nrJ += tm.Day ;
if (tm.Year % 4 == 0 && tm.Month > 2) {
// bissextile
nrJ += 1;
}
}
unsigned long long superMillis() {
/**
Retourne le nombre de millisecondes depuis le démarrage du programme
sous la forme d'un nombre entier sur 64 bits (unsigned long long).
anti bug de l'overflow des 32 bits qui repasse à zéro tous les ~50 jours
*/
static unsigned long nbRollover = 0;
static unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis < previousMillis) {
nbRollover++;
}
previousMillis = currentMillis;
unsigned long long finalMillis = nbRollover;
finalMillis <<= 32;
finalMillis += currentMillis;
return finalMillis;
}