De nombreuses applications manipulent des données sous forme de tableau et il est souvent nécessaire des les stocker dans des fichiers. Ces fichiers peuvent être créés ou exploités par des outils externes comme les logiciels de type tableur (Microsoft Excel, LibreOffice/OpenOffice calc, …). Le format CSV répond à ces besoins en étant un format d’échange non propriétaire et extrêmement simple à gérer.
Le format CSV (Comma-separated values) est un format informatique ouvert représentant des données tabulaires sous forme de valeurs séparées par un délimiteur (initialement des virgules).
Remarque : Le format CSV n’a jamais vraiment fait l’objet d’une spécification formelle. Toutefois, la RFC 4180 décrit la forme la plus courante et établit son type MIME « text/csv
», enregistré auprès de l’IANA.
Les séparateurs ne sont pas standardisés (virgules, points-virgules, etc…) rend ce format peu pratique pour une utilisation autre que des échanges de données ponctuels. Ce format est toutefois très populaire parce qu’il est très facile à générer.
Remarque : de plus en plus de logiciels utilisent le format XML (Extensible Markup Language) pour l’échange de données (voir l’activité sur les fichiers XML).
Les fichiers CSV sont des fichiers texte : ils peuvent donc être manipulés avec un éditeur de texte. Mais les fichiers CSV sont essentiellement utilisés par des logiciels de type tableur (Microsoft Excel, LibreOffice/OpenOffice calc, …).
Chaque ligne du texte correspond à une ligne du tableau et les virgules correspondent aux séparations entre les colonnes. Les portions de texte séparées par une virgule correspondent ainsi aux contenus des cellules du tableau.
Une ligne est une suite ordonnée de caractères terminée par un caractère de fin de ligne (CRLF), la dernière ligne pouvant en être exemptée.
Exemple de fichier CSV :
Sexe,Prénom,Année de naissance
M,Alphonse,1932
F,Béatrice,1964
F,Charlotte,1988
Lorsque l’on ouvre ce type de fichier avec un tableur, celui peut demander à choisir le séparateur à utiliser :
La feuille de calcul que l’on obtient ici :
Remarque : Les champs texte peuvent également être délimités par des guillemets. Lorsqu’un champ contient lui-même des guillemets, ils sont doublés afin de ne pas être considérés comme début ou fin du champ. Si un champ contient un signe utilisé comme séparateur de colonne (virgule, point-virgule, tabulation, etc.) ou comme séparateur de ligne (généralement le caractère de retour à la ligne), les guillemets sont obligatoires afin que ce signe ne soit pas confondu avec un séparateur.
Qt ne fournit pas de classe capable de gérer directement des fichiers CSV. On utilisera donc la classe QFile
qui permet de manipuler des fichiers.
Être capable de lire et écrire dans un fichier CSV des données tabulaires.
On va créer une application GUI qui simule une acquisition de mesures de température et qui les affiche dans un tableau. L’application devra être capable d’enregistrer dans un fichier datas.csv
ces mesures horodatées au format CSV.
Il est possible de choisir le nombre de mesures à réaliser puis, on lance l’acquisition en cliquant sur le bouton Acquérir :
On utilisera le séparateur ‘;
’ et on protégera les données avec des guillemets ‘"
’ :
Horodatage;Température °C
"24/11/2015 12:23";"25,12"
"24/11/2015 12:24";"31,37"
"24/11/2015 12:25";"38,63"
"24/11/2015 12:26";"37,34"
"24/11/2015 12:27";"33,93"
"24/11/2015 12:28";"20,19"
"24/11/2015 12:29";"34,28"
"24/11/2015 12:30";"29,42"
"24/11/2015 12:31";"25,99"
"24/11/2015 12:32";"31,82"
Pour manipuler ces mesures dans le programme, on définira cette structure de données :
typedef struct
{
QString horodatage; // de la forme "dd/MM/yyyy hh:mm"
double valeur; // ici une température en °C
} Mesure;
L’objectif est d’écrire dans un fichier CSV lorsqu’on clique sur le bouton Enregistrer.
Pour cela, on utilisera la méthode ecrireCSV()
:
bool MaFenetre::ecrireCSV()
{
// Le fichier CSV
QFile *fichierCSV = new QFile("datas.csv");
// Ouverture du fichier en mode texte et en écriture seule
if (fichierCSV->open(QFile::WriteOnly | QIODevice::Text))
{
// Ecriture de l'en-tête
QTextStream entete(fichierCSV);
entete << QString::fromUtf8("Horodatage;Température °C") << endl;
}
else
{
QMessageBox::critical(0,"Erreur !",("Impossible d'ouvrir le fichier datas.csv"));
delete fichierCSV;
return false;
}
// Ecriture des données
QTextStream datas(fichierCSV);
QString data;
// on récupère toutes les mesures et on les écrit dans le fichier
int n = 0;
while ( n < mesures.size() )
{
data = mesures[n].horodatage;
datas << "\"" << data << "\""; // on protège la data avec des "
datas << ";";
data = QString::number(mesures[n].valeur);
//data.sprintf("%.2f", mesures[n].valeur);
// A la française ?
data.replace(QString("."), QString(","));
datas << "\"" << data << "\""; // on protège la data avec des "
datas << endl;
++n;
}
// On ferme le fichier
fichierCSV->close();
delete fichierCSV;
return true;
}
Code source complet : test-mo-fichier-csv.zip
La méthode lireCSV()
s’occupera du chargement et de l’affichage des mesures en provenance d’un fichier CSV :
bool MaFenetre::lireCSV(const QString &fichier)
{
// Le fichier CSV
QFile *fichierCSV = new QFile(fichier);
// Ouverture du fichier en mode texte et en écriture seule
if (fichierCSV->open(QFile::ReadOnly | QIODevice::Text))
{
// nouvelle lecture
mesures.clear();
// Lecture des données
QTextStream datas(fichierCSV);
QString ligne;
QString horodatage;
QString valeur;
int nb = 0;
while(!datas.atEnd())
{
ligne = datas.readLine();
// sauf la ligne d'en-tête
if(nb != 0)
{
// traitement des données de la ligne
// on découpe avec le séparateur ';'
horodatage = ligne.section(';', 0, 0);
// on retire les '"'
horodatage.replace(QString("\""), QString(""));
// A la française ?
valeur = ligne.section(';', 1, 1);
// on retire les '"'
valeur.replace(QString("\""), QString(""));
valeur.replace(QString(","), QString("."));
// on lit la mesure horodatée
Mesure mesure;
mesure.horodatage = horodatage;
mesure.valeur = valeur.toDouble();
qDebug() << QString::fromUtf8("<MaFenetre::lireCSV()> %1 : %2 °C").arg(mesure.horodatage).arg(QString::number(mesure.valeur));
// on ajoute la nouvelle mesure lue
mesures.push_back(mesure);
}
++nb;
}
// on met à jour le nombre d'échantillon
editNbMesures->setValue(mesures.size());
// on met à jour l'affichage du tableau
afficher();
}
else
{
QMessageBox::critical(0, "Erreur !", ("Impossible d'ouvrir le fichier datas.csv"));
delete fichierCSV;
return false;
}
// On ferme le fichier
fichierCSV->close();
delete fichierCSV;
return true;
}
Le slot charger()
permet d’ouvrir le fichier CSV de son choix (cf. QFileDialog::getOpenFileName()
) :
void MaFenetre::charger()
{
QString fichier = QFileDialog::getOpenFileName(NULL, QObject::tr("Ouvrir"), ".", "*.csv");
if(!fichier.isEmpty())
lireCSV(fichier);
}
On obtient au final :
Code source complet : test-mo-fichier-csv.zip