Recherche…


Remarques

Le constructeur par défaut de std::istream_iterator construit un itérateur qui représente la fin du flux. Ainsi, std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(), .... signifie copier de la position actuelle dans ifs à la fin.

Flux de chaînes

std::ostringstream est une classe dont les objets ressemblent à un flux de sortie (vous pouvez leur écrire via un operator<< ), mais stocke réellement les résultats de l'écriture et les fournit sous la forme d'un flux.

Considérez le code court suivant:

#include <sstream>
#include <string>                                                                                                                          

using namespace std;

int main()
{
    ostringstream ss;
    ss << "the answer to everything is " << 42;
    const string result = ss.str(); 
}   

La ligne

ostringstream ss;

crée un tel objet. Cet objet est d'abord manipulé comme un flux régulier:

ss << "the answer to everything is " << 42;

Après cela, le flux résultant peut être obtenu comme ceci:

const string result = ss.str();

(le result la chaîne sera égal à "the answer to everything is 42" ).

Ceci est surtout utile lorsque nous avons une classe pour laquelle la sérialisation du flux a été définie et pour laquelle nous voulons une forme de chaîne. Par exemple, supposons que nous ayons une classe

class foo 
{   
    // All sort of stuff here.
};  

ostream &operator<<(ostream &os, const foo &f);

Pour obtenir la représentation sous forme de chaîne d'un objet foo ,

foo f;

nous pourrions utiliser

ostringstream ss; 
ss << f;
const string result = ss.str();        

Le result contient alors la représentation sous forme de chaîne de l'objet foo .

Lire un fichier jusqu'à la fin

Lecture d'un fichier texte ligne par ligne

Une manière appropriée de lire un fichier texte ligne par ligne jusqu'à la fin n'est généralement pas claire dans la documentation ifstream . Considérons quelques erreurs courantes commises par des programmeurs C ++ débutants, et une manière appropriée de lire le fichier.

Lignes sans caractères d'espacement

Par souci de simplicité, supposons que chaque ligne du fichier ne contient aucun symbole d'espacement.

ifstream a l' operator bool() , qui renvoie true lorsqu'un flux ne contient aucune erreur et est prêt à être lu. De plus, ifstream::operator >> renvoie une référence au flux lui-même, nous pouvons donc lire et vérifier EOF (ainsi que les erreurs) sur une seule ligne avec une syntaxe très élégante:

std::ifstream ifs("1.txt");
std::string s;
while(ifs >> s) {
    std::cout << s << std::endl;
}

Lignes avec des caractères d'espacement

ifstream::operator >> lit le flux jusqu'à ce qu'un caractère d' ifstream::operator >> apparaisse, le code ci-dessus imprimera les mots d'une ligne sur des lignes séparées. Pour tout lire jusqu'à la fin de la ligne, utilisez std::getline au lieu de ifstream::operator >> . getline renvoie une référence au thread avec lequel il a travaillé, donc la même syntaxe est disponible:

while(std::getline(ifs, s)) {
    std::cout << s << std::endl;
}

De toute évidence, std::getline devrait également être utilisé pour lire un fichier d'une seule ligne jusqu'à la fin.

Lecture d'un fichier dans un tampon à la fois

Enfin, lisons le fichier du début à la fin sans arrêter aucun caractère, y compris les espaces blancs et les nouvelles lignes. Si nous savons que la taille exacte du fichier ou la limite supérieure de la longueur est acceptable, nous pouvons redimensionner la chaîne et lire ensuite:

s.resize(100);
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    s.begin());

Sinon, il faut insérer chaque caractère à la fin de la chaîne, donc std::back_inserter est ce dont nous avons besoin:

std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::back_inserter(s));

Alternativement, il est possible d'initialiser une collection avec des données de flux, en utilisant un constructeur avec des arguments de plage d'itérateurs:

std::vector v(std::istreambuf_iterator<char>(ifs),
    std::istreambuf_iterator<char>());

Notez que ces exemples sont également applicables si ifs est ouvert en tant que fichier binaire:

std::ifstream ifs("1.txt", std::ios::binary);

Copier des flux

Un fichier peut être copié dans un autre fichier avec des flux et des itérateurs:

std::ofstream ofs("out.file");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::ostream_iterator<char>(ofs));
ofs.close();

ou redirigé vers un autre type de flux avec une interface compatible. Par exemple flux de réseau Boost.Asio:

boost::asio::ip::tcp::iostream stream;
stream.connect("example.com", "http");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::ostream_iterator<char>(stream));
stream.close();

Tableaux

Comme les itérateurs peuvent être considérés comme une généralisation de pointeurs, les conteneurs STL dans les exemples ci-dessus peuvent être remplacés par des tableaux natifs. Voici comment analyser les nombres dans un tableau:

int arr[100];
std::copy(std::istream_iterator<char>(ifs), std::istream_iterator<char>(), arr);

Méfiez-vous du débordement de la mémoire tampon, car les tableaux ne peuvent pas être redimensionnés à la volée après leur attribution. Par exemple, si le code ci-dessus est alimenté par un fichier contenant plus de 100 nombres entiers, il essaiera d'écrire en dehors du tableau et aura un comportement indéfini.

Impression de collections avec iostream

Impression de base

std::ostream_iterator permet d'imprimer le contenu d'un conteneur STL sur n'importe quel flux de sortie sans boucles explicites. Le second argument du constructeur std::ostream_iterator définit le délimiteur. Par exemple, le code suivant:

std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ! "));

imprimera

1 ! 2 ! 3 ! 4 !

Type de distribution implicite

std::ostream_iterator permet de transtyper implicitement le type de contenu du conteneur. Par exemple, accordons std::cout pour imprimer des valeurs à virgule flottante avec 3 chiffres après le point décimal:

std::cout << std::setprecision(3);
std::fixed(std::cout);

et instancier std::ostream_iterator avec float , alors que les valeurs contenues restent int :

std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<float>(std::cout, " ! "));

donc le code ci-dessus donne

1.000 ! 2.000 ! 3.000 ! 4.000 !

malgré std::vector tient int s.

Génération et transformation

std::generate , std::generate_n et std::transform fournissent un outil très puissant pour la manipulation des données à la volée. Par exemple, avoir un vecteur:

std::vector<int> v = {1,2,3,4,8,16};

nous pouvons facilement imprimer la valeur booléenne de l'instruction "x is even" pour chaque élément:

std::boolalpha(std::cout); // print booleans alphabetically
std::transform(v.begin(), v.end(), std::ostream_iterator<bool>(std::cout, " "),
[](int val) {
    return (val % 2) == 0;
});

ou imprimer l'élément carré:

std::transform(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "),
[](int val) {
    return val * val;
});

Impression de N nombres séparés par des espaces:

const int N = 10;
std::generate_n(std::ostream_iterator<int>(std::cout, " "), N, std::rand);

Tableaux

Comme dans la section sur la lecture des fichiers texte, presque toutes ces considérations peuvent être appliquées aux tableaux natifs. Par exemple, imprimons les valeurs au carré d'un tableau natif:

int v[] = {1,2,3,4,8,16};
std::transform(v, std::end(v), std::ostream_iterator<int>(std::cout, " "),
[](int val) {
    return val * val;
});

Fichiers d'analyse

Analyse des fichiers dans des conteneurs STL

istream_iterator s sont très utiles pour lire des séquences de nombres ou d'autres données analysables dans des conteneurs STL sans boucles explicites dans le code.

En utilisant une taille de conteneur explicite:

std::vector<int> v(100);
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
    v.begin());

ou en insérant un itérateur:

std::vector<int> v;
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
    std::back_inserter(v));

Notez que les nombres dans le fichier d'entrée peuvent être divisés par un nombre quelconque de caractères d'espacement et de nouvelles lignes.

Analyse de tables de texte hétérogènes

Au istream::operator>> mesure que istream::operator>> lit le texte jusqu'à un symbole d' istream::operator>> , il peut être utilisé dans une condition while pour analyser des tables de données complexes. Par exemple, si nous avons un fichier avec deux nombres réels suivis d'une chaîne (sans espaces) sur chaque ligne:

1.12 3.14 foo
2.1 2.2 barr

il peut être analysé comme ceci:

std::string s;
double a, b;
while(ifs >> a >> b >> s) {
    std::cout << a << " " << b << " " << s << std::endl;
}

Transformation

Toute fonction de manipulation de plage peut être utilisée avec les plages std::istream_iterator . L'un d'eux est std::transform , qui permet de traiter des données à la volée. Par exemple, lisons les valeurs entières, multiplions-les par 3.14 et stockez le résultat dans un conteneur à virgule flottante:

std::vector<double> v(100);
std::transform(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
v.begin(),
[](int val) {
    return val * 3.14;
});


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow