Bonjour à toutes et à tous,
Je patauge lamentablement. Je voudrais concaténer un "/" à une const char * (en l’occurrence file.name) pour obtenir une nouvelle const char *.
Merci de votre aide avant que je devienne fou
.
Cordialement.
Pierre.
Bonjour à toutes et à tous,
Je patauge lamentablement. Je voudrais concaténer un "/" à une const char * (en l’occurrence file.name) pour obtenir une nouvelle const char *.
Merci de votre aide avant que je devienne fou
.
Cordialement.
Pierre.
Tu va me haïr, tu peux mettre ton code ?
si tu utilise un const char*, tu ne peux plus changer son contenue une fois celui-ci initialiser.
Tu veux concaténer dans un nouveau const char ?
Oui. J'ai un fichier représenté par file.name() qui est une const char *. Il faut que je lui ajoute un "/" qui représente le chemin pour former une nouvelle const char * pour envoyer cela dans la fonction suivante :
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\r\n", path);
if(fs.remove(path)){
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
Cordialement.
Pierre.
Tu ne peux pas modifier un const char *, sinon ce n'est plus un const
tu dois faire quelque chose comme ça, attention c'est un peu bête de réserver directement dans la pile, il aurait mieux valu le faire avec une variable globale.
ou alors mieux, tu fais une allocation dynamique(malloc) de uniquement de l'espace dont tu as besoin, soit un malloc, un strcpy et un strcat sur ton buffer dynamique qui aura la taille de file.name + 1('/') + 1(Null de fin de chaine)
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
}
void printMessage(const char *message) {
// Affiche le message reçu
Serial.println(message);
}
void loop() {
const char * path = "toto/titi";
char filePath[2048] = "/";
strcat(filePath, path);
Serial.print("Cat:");printMessage(filePath);
// put your main code here, to run repeatedly:
delay(10); // this speeds up the simulation
}
comme notre compilateur supporte les tableaux à dimension variable (qui ne changent pas mais qui ne sont pas connues à la compilation) on n'est pas obligé de mettre 2048 en dur, on peut s'adapter à la taille du chemin.
void deleteFile(/* fs::FS &fs, */ const char * path) {
if (path != nullptr) {
size_t newSize = strlen(path) + 2; // nouvelle taille = ancienne longueur + 1 pour le / + 1 pour le caractère nul
char newPath[newSize]; // on crée un nouveau buffer (modifiable)
strlcpy(newPath, path, newSize); // on recopie l'ancien path
newPath[newSize - 2] = '/'; // on rajoute le / à la fin
newPath[newSize - 1] = '\0'; // on s'assure que la c-string est bien terminée
Serial.print("Ancien nom ["); Serial.print(path); Serial.println("]");
Serial.print("Nouveau nom ["); Serial.print(newPath); Serial.println("]");
/*
if (fs.remove(newPath)) {
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
*/
}
}
void setup() {
Serial.begin(115200);
deleteFile("/tmp/toto");
}
void loop() {}
une petite amélioration serait de tester si le dernier caractère est déjà un / et dans ce cas on ne rajouter rien.
Merci pour ces précisions qui m’ont permis d'avancer un peu.
Pour autant, c'est la patauge la plus complète.
J'ai une fonction qui doit remplacer un fichier par un autre. Je voudrais qu'elle me retourne un const char * ou un String pour autant qu'on puisse convertir ce String en const char *. J'ai besoin d'un const char * comme paramètre pour des traitements ultérieurs de fichiers.
Voilà le code que j'ai :
String pathHisto(const char * fch) {
char filePath[24] = "/";
strcat(filePath, fch);
return String(filePath);
}
String remplaceFchHisto() {
strftime(info_DH, 24, "%a-%d-%m-%y.csv", &timeinfo);
File root = LittleFS.open("/");
File file = root.openNextFile();
const char *filePath;
bool vu = false;
while(file) {
if(String(file.name()).startsWith(String(info_DH).substring(0, 3))){
filePath = pathHisto(file.name()).c_str(); // Fichier à supprimer. Pas sûr que cette ligne fonctionne.
vu = true;
}
if (vu == true)
break;
else{
file = root.openNextFile();
}
}
file = LittleFS.open(pathHisto(info_DH), FILE_WRITE); // Création du nouveau fichier
file.close();
LittleFS.remove(filePath); // Suppression de l'ancien fichier*/
return pathHisto(info_DH);
}
La première ligne me retourne dans info_DH (char info_DH[24]; ) le nom du fichier que je veux créer. Par exemple : Sat-25-01-25.csv
L'algorithme qui suit sert à voir si un fichier commençant par le même nom de jour existe. Si oui, ce fichier est remplacé par le nouveau. De cette manière, je crée 7 fichiers (un par nom de jour) qui sont remplacés toutes les semaines. Cela me crée un historique glissant d'une durée d'une semaine.
L'algorithme fonctionne. Ce qui me cause problème est le retour de la fonction qui devrait me donner le nom de la nouvelle fonction.
Telle qu'elle est écrite, cela me retourne un String. Problème : quand je convertis ce String en const char * avec la fonction .c_str(), ça renvoie n'importe quoi.
J’aimerais que ma fonction me retourne directement un const char *.
Merci de votre aide. (Je cherche toujours de mon côté, mais je patauge
)
Pierre.
Si vous souhaitez appeler plusieurs fois la fonction qui modifie le nom et ensuite conserver en mémoire les nom retournés (ie vous demander à changer fichier1 et fichier2 et vous avez besoin des deux noms modifiés ensuite, la fonction sera obligée d’avoir un buffer dédié pour chaque appel et par définition non constant (mais c’est pas grave) puisque vous voulez construire le nouveau nom de fichier dans ce buffer.
Si vous n’avez besoin que d’une seule copie active, dans ce cas le buffer peut être statique et alloué dans la fonction.
Dans le premier cas, le plus simple sans doute pour vous c’est de passer par une String’, le compilo se chargera de détruire les copies intermédiaires pour vous et vous n’avez pas à gérer de l’allocation dynamique et libérer la mémoire ou gérer un buffer à passer à la fonction. Et pour passer d’une String à son const char * sous jacent, vous appellerez .c_str() sur la chaîne.
Dans le second cas, la fonction retourne juste un pointeur sur son tableau local declare comme static (et assez grand pour la plus grande des chaînes).
Merci J-M-L pour ces éclaircissements.
J'ai remanié de mon côté ma fonction qui est plus simple et qui fonctionne ... presque :
const char * remplaceFchHisto() {
strftime(info_DH, 24, "/%a-%d-%m-%y.csv", &timeinfo);
Serial.print("new ");
Serial.println(info_DH);
File root = LittleFS.open("/");
File file = root.openNextFile();
char filePath[24] = "/";
bool vu = false;
while(file) {
if(String(file.name()).startsWith(String(info_DH).substring(0, 4))){
LittleFS.remove(file.path()); // Suppression de l'ancien fichier
file.close();
vu = true;
}
if (vu == true)
break;
else{
file = root.openNextFile();
}
}
if (!LittleFS.exists(info_DH))
file = LittleFS.open(info_DH, FILE_WRITE); // Création du nouveau fichier
file.close();
return info_DH;
}
Je me sers de la variable info_DH pour y stocker le nom du fichier. Lorsque je sors de cette fonction, avec un Serial.println() je vois bien mon nom de fonction ... mais cela ne dure pas car info_DH est utilisé cycliquement pour contenir des infos de date et heure ... et mon nom de fichier se retrouve être les dernières données de date et heure.
Comme vous le dites, c'est une question de buffer. Ce que retourne ma fonction n'est pas une donnée, mais l'adresse de info_DH et, comme son contenu change au fil du temps, mon nom de fichier n'est plus ce qu'il devrait être.
J'ai déclaré une nouvelle variable pour mettre mon nom de fichier : char nom_Fch[24]; et elle ne sera utilisée qu'à cela --> ça fonctionne.
Merci beaucoup.
Cordialement.
Pierre.
C’est quoi son type?
C’est assez confus votre fonction avec des String a tout va… il faudrait connaître les types de toutes ces variables globales que vous utilisez
le même que celui que j'ai donné à nom_Fch : char info_DH[24];
Il n'y a que deux référence aux String :
if(String(file.name()).startsWith(String(nom_Fch).substring(0, 4))){
J'ai pris ça sur la toile. Mais si on sait faire sans les String, ça me convient.
Mis à part LittleFS et struct tm timeinfo; qui vient de la bibliothèque time, il n'y a pas d'autres variables globales.
Cordialement.
Pierre.
Ah oui j’avais pas vu que file était locale
En restant avec des cString vous pourer utiliser strncmp() pour cela
strncmp() ne fonctionne pas dans ce cas précis car ce n'est pas la position dans le texte qui est prise en compte, mais seulement le nombre de caractères composant la partie commune. Par exemple : onde.csv donne un résultat positif en comparaison avec Sun-26-01-25.csv.
Tous mes fichiers se correspondront car ils ont la même extension.
Cordialement.
Pierre.
si j'ai bien compris
String(file.name()).startsWith(String(info_DH).substring(0, 4))
veut dire
prendre le nom du fichier et cours et vérifier si les 4 premiers caractères sont les même que ceux de info_DH.
donc à mon avis c'est ce que vous pouvez faire avec
if (strncmp(file.name(), info_DH, 4) == 0) {
// oui ça commence pareil
}
non?
Ben non. Comme je l'ai dit précédemment, s'il se trouve d'autres fichiers ayant la même extension, strncmp() va les considérer comme égaux.
Ou alors, il faut que j'extrais les premiers caractères de info_DH pour faire la comparaison. D'où un substring ...
Cordialement.
Pierre.
je ne comprends pas ce que vous dites , on ne va pas regarder l'extension.
imaginons que vous ayez comme résultat de strftime
char info_DH[] = "Sun-26-01-25.csv"; // strftime(info_DH, 24, "%a-%d-%m-%y.csv", &timeinfo);
quand vous faites String(info_DH).substring(0, 4) vous allez extraire les 4 premiers caractères donc Sun-
et donc l'expression que vous écrivez
if(String(file.name()).startsWith(String(info_DH).substring(0, 4))) {
...
}
vous regardez bien si le nom du fichier commence (startsWith) par Sun-. ça ne va pas chercher les fichiers .csv si c'est ça que vous vouliez faire.
➜ c'est tout ce que fait votre test, je ne comprends pas pourquoi vous me parlez.
Ah, je crois qu'il y a peut être malentendu :
Avez vous vu que je propose strncmp() et pas strcmp() peut-être ➜ le n limite le nombre de caractères que l'on compare, j'ai mis 4 puisque vous aviez extrait les 4 premieres lettres de info_DH
Non, il n'y a pas de malentendu, c'est bien la fonction strncmp que j'ai employée :
const char * recherche() {
strftime(nom_Fch, 24, "/%a-%d-%m-%y.csv", &timeinfo);
File root = LittleFS.open("/");
File file = root.openNextFile();
bool vu = false;
while(file) {
if (strncmp(file.name(), nom_Fch, 4)) {
Serial.print("Fch1 ");
Serial.print(file.name());
Serial.print(" Fch2 ");
Serial.print(nom_Fch);
Serial.println(" Vu");
vu = true;
}
if (vu == true)
break;
else{
file = root.openNextFile();
}
}
return nom_Fch;
}
et c'est bien cette fonction qui m'a ressorti l'égalité entre onde.csv et Sun-26-01-25.csv (contiennent tous les deux .csv).
Si ,dans l'ordre des fichiers parcourus, j'avais eu un Sun-JJ-MM-AA.csv avant onde.csv ma fonction aurait ressorti Sun-JJ-MM-AA.csv (égalité sur /Sun), mais manque de chance, elle était après.
Cordialement.
Pierre.
Ce que vous dites ne fait pas de sens. Le test porte sur les 4 premiers caractères donc .csv n'est jamais comparé...
Mais comme je disais plus haut
➜ vous avez oublié le == 0 (la fonction retourne 0 quand il y a un match)
essayez avec
if (strncmp(file.name(), nom_Fch, 4) == 0) {
...
vous ne cherchez que le nom des jours, c'est ça que vous cherchez à faire ?
Et oui, encore une faute d’inattention. Dans ma version avec les String, ce qui était dans le if était un boolean, donc vrai ou faux en lui-même sans avoir à le comparer à une valeur de même type.
Heureusement. vous avez l’œil.
NOTA : oui, ce sont seulement les noms de jour qui m'intéressent.
Cordialement.
Pierre.
Oui c’était une valeur de vérité