Merci, j'ignorais cette finesse.
Moi, j'aurais écrit
Mais cela est-il bien dans l'esprit d'un CSV?Citation:
A1;B1;C1
A2;B\\n2;C2
ou
A1;B1;C1
A2;"B\n2";C2
ou même
A1;B1;C1
A2;"B\\n2";C2
Version imprimable
Merci, j'ignorais cette finesse.
Moi, j'aurais écrit
Mais cela est-il bien dans l'esprit d'un CSV?Citation:
A1;B1;C1
A2;B\\n2;C2
ou
A1;B1;C1
A2;"B\n2";C2
ou même
A1;B1;C1
A2;"B\\n2";C2
Salut,
De manière générale, tu ne pourra pas utiliser une formule simple pour déterminer l'offset du fichier auquel tu dois aller pour lire la Nième donnée.
La raison est simple: le nombre de caractères qui composent l'ensemble des informations relatives à une donnée varie beaucoup trop:
utilise 11 caractèresCode:1;;GEN_1;;x
en utilise déjà 13... Et je ne parle pas deCode:10;;GEN_10;;x
qui en utilise 25 ni deCode:0;A16;GEN_0;Type carter;x
pour lequel je renonce à compter :aie:Code:28;D16;GEN_28;Dernière OP travaillée;x
De plus, il faut se rappeler que les temps d'accès à un fichier sont particulièrement grand comparer aux temps d'accès à la mémoire.
Il y a donc très largement intérêt à lire l'ensemble du fichier en une fois de manière à créer une collection (un tableau) de données permettant de représenter les différentes informations contenues dans le fichier.
Cela pourrait se baser sur une structure proche de
(ou l'équivalent MFC).Code:
1
2
3
4
5
6
7
8 struct Data { int octet; std::string type; std::string variable; std::string affichage; bool archive; };
Tu commencerais, au lancement de l'application, par lire ton fichier, ligne par ligne, et par remplir un tableau de Data dont les différents champs seraient définis sur base de ce que tu lis dans le fichier.
Tout le reste du travail s'effectuerait sur base de se tableau.
Il ne faudra pas oublier de sauvegarder les données au plus tard juste avant de quitter l'application si elle y a apporté des modifications / ajouts ;)
Bonjour,
alors j'ai essayé pas mal de truc. Je pense que le plus important à l'heure actuelle, c'est que je réussie à detecter une chaine de caractère, par exemple trouver la colonne "variable". Est ce que je peux jouer avec le numéro de colonne, puisque la colonne variable est toujours au même endroit. Ensuite rechercher dans toute cette colonne les "GEN_XX" puis recuperer les données associées.
Cependant je ne voit donc pas comment dire "va chercher toujours les données de la colonne 3". Et comment incrementer mon string "GEN_XX" ?
J'ai l'impression que tu ne prends pas la bonne approche. Relis bien le message de Koala.
L'idée, c'est que tu lises tout ton fichier, et qu'au fur et à mesure de la lecture, tu remplisses un std::vector de ta structure Data. Pour chaque enregistrement, tu peux récupérer facilement les valeur de la colonne 0, 1, 2, etc, et les associer à la valeur correspondante de la structure data.
Ensuite, tu pourras parcourir ce vector pour retourner, par exemple, un nouveau std::vector, de std::string cette fois-ci, contenant toute la liste des données de la colonne 3.
Me revoilà,
alors, j'ai pas mal cherché, et j'ai trouvé l'equivalent d'une fonction split pour MFC. Cette fonction est censée me retourner un tableau dans lequel sont inscrits tous les champs lus, ça m'aidera surement a bien me retrouver par la suite. Mais sans resultats pour le moment. Si vous avec une petite idée.
La fonction principale
La fonction splitCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 FILE * fichierCsv; // Nom du fichier qu'on va utiliser char * cToken; // Buffer du contenu des valeurs d'une ligne char * cToken2; // Buffer du contenu des valeurs d'une ligne char cBuffligne[1500] = ""; // Buffer du contenu de la ligne du fichier CString ligne; int iCompteur = 0; // Compte le nombre de fois où on boucle int colonneProprietaire; CString delimiter = _T(";"); CStringArray result; if(( fichierCsv = fopen ("mapping.csv","r")) != NULL)//Si pas de problème lors de l'ouverture du fichier { while(fgets(cBuffligne,sizeof(cBuffligne),fichierCsv)!= NULL)//pour toute les lignes du fichier ou jusqu'a ce que "d" soit faux { ligne = _T(""); for(int i = 0 ; i<sizeof(cBuffligne); i++) { ligne += cBuffligne[i]; } SplitString(ligne,delimiter,result); }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 int CCsvDlg::SplitString(const CString& input, const CString& delimiter, CStringArray& results) { int iPos = 0; int newPos = -1; int sizeS2 = delimiter.GetLength(); int isize = input.GetLength(); CArray<INT, int> positions; newPos = input.Find (delimiter, 0); if( newPos < 0 ) { return 0; } int numFound = 0; while( newPos > iPos ) { numFound++; positions.Add(newPos); iPos = newPos; newPos = input.Find (delimiter, iPos+sizeS2+1); } for( int i=0; i <= positions.GetSize(); i++ ) { CString s; if( i == 0 ) s = input.Mid( i, positions[i] ); else { int offset = positions[i-1] + sizeS2; if( offset < isize ) { if( i == positions.GetSize() ) s = input.Mid(offset); else if( i > 0 ) s = input.Mid( positions[i-1] + sizeS2, positions[i] - positions[i-1] - sizeS2 ); } } if( s.GetLength() > 0 ) results.Add(s); } return numFound; }
Le problème n'est pas dans le code, il est avant tout algorithmique. Il faut d'abord trouver l'algorithme qui répond à ton problème, sinon se lancer dans l'écriture d'un code approximatif ne servira pas à grand chose.
Ici tu as plusieurs étapes, qui peuvent être fait en parallèle ou pas :
- lire le contenu du fichier
- identifier chaque ligne du fichier
- splitter chaque ligne selon le caractère ';'
- remplir une structure en mémoire correspondant au contenu de ton fichier
Dans le code que tu montres, il manque la dernière étape. Cela dit, je pense que tu as les éléments pour les faire.
C'est ce que je fais, j'ouvre mon fichier, je recupere la ligne, je split, et j'envoie vers une structure (enfin j'essaie, j'ai declaré ma structure, mais quand je fais mapping.variable, il crash)
Désolé mais si tu ne postes pas le code qui plante, ça va être difficile de t'aider.
Dans le code que tu as posté, je ne vois ni la structure, ni le code qui ajoute des choses dedans...
Désolé, j'ai avancé, donc ça remplit pas ma structure. mon result[0] à toujours la même valeur, malgrès que je change de ligne
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 void CCsvDlg::OuvrirCsv() { FILE * fichierCsv; // Nom du fichier qu'on va utiliser char cBuffligne[150] = ""; // Buffer du contenu de la ligne du fichier CString ligne; CString delimiter = _T(";"); CStringArray result; CString tab = _T(""); if(( fichierCsv = fopen ("mapping.csv","r")) != NULL)//Si pas de problème lors de l'ouverture du fichier { MAPPING mapping; //if (fgets(cBuffligne,sizeof(cBuffligne),fichierCsv) != NULL) while(fgets(cBuffligne,sizeof(cBuffligne),fichierCsv)!= NULL)//pour toute les lignes du fichier ou jusqu'a ce que "d" soit faux { ligne = CString(cBuffligne); SplitString(ligne,delimiter,result); mapping.variable = result[0] } }fclose(fichierCsv); }
et ma structure
Edit : probleme resolu, le CString results est alloué à chaque changements de ligneCode:
1
2
3
4
5
6
7
8 typedef struct { CString variable; CString activer; int octet; CString affichage; CString type; }MAPPING;
CStdioFile en MFC non ? Avec CStdioFile::ReadString ça t'évitera d'horribles lignes du genre char cBuffligne[150] = ""; :mouarf:
Et si tu restes 100% MFC, il me semble me souvenir d'un CArray qui pourrait faire l'affaire pour stocker tes lignes.
A la volée (car je n'ai pas de MFC sous la main), ce devrait être quelque chose comme ça :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void CCsvDlg::OuvrirCsv() { CStdioFile fichier; CString ligne; CString delimiter = _T(";"); CStringArray result; CArray<MAPPING> tableau_resultat; if(( fichier.Open(_T("mapping.csv"),CFile::modeWrite)))//Si pas de problème lors de l'ouverture du fichier { MAPPING mapping; while(fichier.ReadString(ligne))//pour toute les lignes du fichier ou jusqu'a ce que "d" soit faux { SplitString(ligne,delimiter,result); mapping.variable = result[0]; tableau_resultat.Add (mapping); } } }