Suche…


Bemerkungen

Der Standardkonstruktor von std::istream_iterator einen Iterator, der das Ende des Streams darstellt. Daher bedeutet std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(), .... das Kopieren von der aktuellen Position in ifs zum Ende.

String-Streams

std::ostringstream ist eine Klasse, deren Objekte wie ein Ausgabestrom aussehen ( std::ostringstream Sie können sie mit dem operator<< schreiben), sie speichern jedoch die Schreibergebnisse und stellen sie in Form eines Streams bereit.

Betrachten Sie den folgenden Kurzcode:

#include <sstream>
#include <string>                                                                                                                          

using namespace std;

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

Die Linie

ostringstream ss;

erstellt ein solches Objekt. Dieses Objekt wird zuerst wie ein regulärer Stream bearbeitet:

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

Im Anschluss daran kann der resultierende Stream jedoch folgendermaßen erhalten werden:

const string result = ss.str();

(Das String- result ist gleich "the answer to everything is 42" ).

Dies ist vor allem dann nützlich, wenn wir eine Klasse haben, für die Stream-Serialisierung definiert wurde und für die wir ein String-Formular haben möchten. Angenommen, wir haben eine Klasse

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

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

Um die Zeichenfolgendarstellung eines foo Objekts zu erhalten,

foo f;

wir könnten gebrauchen

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

Das result enthält dann die Zeichenfolgendarstellung des foo Objekts.

Lesen einer Datei bis zum Ende

Eine Textdatei zeilenweise lesen

Eine geeignete Methode, eine Textdatei Zeile für Zeile bis zum Ende zu lesen, ist in der Regel nicht aus der Dokumentation von ifstream . Betrachten wir einige häufige Fehler, die von Anfängern von C ++ - Programmierern begangen wurden, und eine geeignete Methode zum Lesen der Datei.

Zeilen ohne Whitespace-Zeichen

Der Einfachheit halber nehmen wir an, dass jede Zeile in der Datei keine Leerzeichen enthält.

ifstream hat den operator bool() , der true zurückgibt, wenn ein Stream fehlerfrei ist und zum Lesen bereit ist. Darüber hinaus gibt ifstream::operator >> einen Verweis auf den Stream selbst zurück, sodass wir EOF (sowie Fehler) in einer Zeile mit sehr eleganter Syntax lesen und überprüfen können:

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

Zeilen mit Whitespace-Zeichen

ifstream::operator >> liest den Stream, bis ein Leerzeichen auftritt, sodass der obige Code die Wörter aus einer Zeile in separaten Zeilen druckt. Um alles bis zum Zeilenende zu lesen, verwenden Sie std::getline anstelle von ifstream::operator >> . getline gibt den Verweis auf den Thread zurück, mit dem er gearbeitet hat, daher ist dieselbe Syntax verfügbar:

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

std::getline sollte std::getline auch bis zum Ende zum Lesen einer einzeiligen Datei verwendet werden.

Eine Datei sofort in einen Puffer lesen

Schließlich lesen wir die Datei vom Anfang bis zum Ende, ohne bei einem beliebigen Zeichen, einschließlich Leerzeichen und Zeilenumbrüchen, anzuhalten. Wenn wir wissen, dass die genaue Dateigröße oder Obergrenze der Länge akzeptabel ist, können wir die Größe der Zeichenfolge ändern und dann lesen:

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

Andernfalls müssen wir jedes Zeichen an das Ende der Zeichenfolge einfügen. std::back_inserter benötigen wir std::back_inserter :

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

Alternativ ist es möglich, eine Sammlung mit Streamdaten zu initialisieren, indem ein Konstruktor mit Iteratorbereichsargumenten verwendet wird:

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

Beachten Sie, dass diese Beispiele auch anwendbar sind, wenn ifs als Binärdatei geöffnet ist:

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

Streams kopieren

Eine Datei kann in eine andere Datei mit Streams und Iteratoren kopiert werden:

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

oder mit einer kompatiblen Schnittstelle zu einem anderen Stream-Typ umgeleitet. Beispiel: Boost.Asio-Netzwerkstream:

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();

Arrays

Da Iteratoren als Verallgemeinerung von Zeigern betrachtet werden können, können STL-Container in den obigen Beispielen durch native Arrays ersetzt werden. So analysieren Sie Zahlen in ein Array:

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

Beachten Sie den Pufferüberlauf, da die Größe der Arrays nach der Zuweisung nicht sofort geändert werden kann. Wenn der obige Code beispielsweise mit einer Datei gespeist wird, die mehr als 100 Integer-Zahlen enthält, wird versucht, außerhalb des Arrays zu schreiben und in undefiniertes Verhalten zu geraten.

Kollektionen mit Iostream drucken

Grundlegendes Drucken

std::ostream_iterator können Sie den Inhalt eines STL-Containers ohne explizite Schleifen in einen beliebigen Ausgabestrom drucken. Das zweite Argument des std::ostream_iterator Konstruktors legt das Trennzeichen fest. Zum Beispiel den folgenden Code:

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

wird drucken

1 ! 2 ! 3 ! 4 !

Implizite Typumwandlung

std::ostream_iterator kann der Inhaltstyp des Containers implizit umgewandelt werden. std::cout wir zum Beispiel std::cout , um Fließkommazahlen mit 3 Stellen nach dem Dezimalpunkt zu drucken:

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

und instanziieren std::ostream_iterator mit float , während die enthaltenen Werte int bleiben:

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

der obige Code ergibt also

1.000 ! 2.000 ! 3.000 ! 4.000 !

trotz std::vector gilt int s.

Erzeugung und Transformation

std::generate , std::generate_n und std::transform bieten ein sehr leistungsfähiges Werkzeug für die schnelle Datenmanipulation. Zum Beispiel mit einem Vektor:

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

Wir können den booleschen Wert der Anweisung "x is even" für jedes Element einfach drucken:

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;
});

oder drucken Sie das quadratische Element:

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

N durch Leerzeichen getrennte Zufallszahlen drucken:

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

Arrays

Wie im Abschnitt zum Lesen von Textdateien können fast alle diese Überlegungen auf native Arrays angewendet werden. Lassen Sie uns zum Beispiel quadratische Werte aus einem nativen Array drucken:

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;
});

Dateien analysieren

Dateien in STL-Container analysieren

istream_iterator s ist sehr nützlich, um Zahlenfolgen oder andere analysierbare Daten in STL-Container ohne explizite Schleifen im Code zu lesen.

Explizite Containergröße verwenden:

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

oder beim Einfügen des Iterators:

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

Beachten Sie, dass die Zahlen in der Eingabedatei durch eine beliebige Anzahl von Leerzeichen und Zeilenumbrüchen geteilt werden können.

Analyse heterogener Texttabellen

Da istream::operator>> Text bis zu einem Leerzeichen liest, kann er in while werden, um komplexe Datentabellen zu parsen. Wenn wir zum Beispiel eine Datei mit zwei reellen Zahlen haben, gefolgt von einer Zeichenfolge (ohne Leerzeichen) in jeder Zeile:

1.12 3.14 foo
2.1 2.2 barr

Es kann wie folgt analysiert werden:

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

Transformation

std::istream_iterator Bereichen std::istream_iterator kann jede Bereichsmanipulationsfunktion verwendet werden. Eines davon ist std::transform , mit dem Daten im laufenden Betrieb verarbeitet werden können. Lassen Sie uns beispielsweise Ganzzahlwerte lesen, mit 3,14 multiplizieren und das Ergebnis in einem Gleitkommabehälter speichern:

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow