La lecture d'un fichier ligne par ligne en C++ peut se faire de différentes manières.
[Rapide] Boucle avec std::getline()
L'approche la plus simple est d'ouvrir un std::ifstream et de boucler en utilisant des appels std::getline(). Le code est propre et facile à comprendre.
#include <fstream>
std::ifstream file(FILENAME);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
file.close();
}
[Rapide] Utiliser le fichier_description_source de Boost.
Une autre possibilité consiste à utiliser la bibliothèque Boost, mais le code est un peu plus verbeux. Les performances sont assez similaires au code ci-dessus (Loop avec std::getline()).
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <fcntl.h>
namespace io = boost::iostreams;
void readLineByLineBoost() {
int fdr = open(FILENAME, O_RDONLY);
if (fdr >= 0) {
io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
io::stream <io::file_descriptor_source> in(fdDevice);
if (fdDevice.is_open()) {
std::string line;
while (std::getline(in, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
fdDevice.close();
}
}
}
[Le plus rapide] Utiliser le code C
Si les performances sont essentielles pour votre logiciel, vous pouvez envisager d'utiliser le langage C. Ce code peut être 4 à 5 fois plus rapide que les versions C++ ci-dessus, voir le benchmark ci-dessous
FILE* fp = fopen(FILENAME, "r");
if (fp == NULL)
exit(EXIT_FAILURE);
char* line = NULL;
size_t len = 0;
while ((getline(&line, &len, fp)) != -1) {
// using printf() in all tests for consistency
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
Benchmark -- Lequel est le plus rapide ?
J'ai effectué quelques tests de performance avec le code ci-dessus et les résultats sont intéressants. J'ai testé le code avec des fichiers ASCII qui contiennent 100 000 lignes, 1 000 000 lignes et 10 000 000 lignes de texte. Chaque ligne de texte contient en moyenne 10 mots. Le programme est compilé avec -O3
et sa sortie est transmise à /dev/null
afin de supprimer la variable de temps d'enregistrement de la mesure. Enfin, et ce n'est pas le moins important, chaque morceau de code enregistre chaque ligne avec la balise printf()
par souci de cohérence.
Les résultats montrent le temps (en ms) que chaque morceau de code a pris pour lire les fichiers.
La différence de performance entre les deux approches C++ est minime et ne devrait pas faire de différence en pratique. La performance du code C est ce qui rend le benchmark impressionnant et peut changer la donne en termes de vitesse.
10K lines 100K lines 1000K lines
Loop with std::getline() 105ms 894ms 9773ms
Boost code 106ms 968ms 9561ms
C code 23ms 243ms 2397ms