Antworten:
Machen Sie zuerst eine ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
Die zwei Standardmethoden sind:
Angenommen, jede Zeile besteht aus zwei Zahlen und liest Token für Token:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Zeilenbasiertes Parsen mit String-Streams:
#include <sstream>
#include <string>
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int a, b;
if (!(iss >> a >> b)) { break; } // error
// process pair (a,b)
}
Sie sollten (1) und (2) nicht mischen, da das tokenbasierte Parsen keine Zeilenumbrüche verschlingt, sodass Sie möglicherweise falsche Leerzeilen erhalten, wenn Sie getline()
nach der tokenbasierten Extraktion das Ende von a erreichen Linie bereits.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
Konstrukts und zur Fehlerbehandlung finden Sie in diesem (meinem) Artikel: gehrcke.de/2011/06/… (Ich glaube, ich brauche kein schlechtes Gewissen, um dies hier zu posten. datiert diese Antwort).
Verwenden Sie ifstream
diese Option , um Daten aus einer Datei zu lesen:
std::ifstream input( "filename.ext" );
Wenn Sie wirklich Zeile für Zeile lesen müssen, gehen Sie folgendermaßen vor:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Aber Sie müssen wahrscheinlich nur Koordinatenpaare extrahieren:
int x, y;
input >> x >> y;
Aktualisieren:
In Ihrem Code verwenden Sie ofstream myfile;
jedoch die o
in ofstream
steht für output
. Wenn Sie aus der Datei (Eingabe) lesen möchten, verwenden Sie ifstream
. Wenn Sie sowohl lesen als auch schreiben möchten, verwenden Sie fstream
.
Das zeilenweise Lesen einer Datei in C ++ kann auf verschiedene Arten erfolgen.
Der einfachste Ansatz besteht darin, einen std :: ifstream und eine Schleife mit std :: getline () -Aufrufen zu öffnen. Der Code ist sauber und leicht zu verstehen.
#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();
}
Eine andere Möglichkeit ist die Verwendung der Boost-Bibliothek, aber der Code wird etwas ausführlicher. Die Leistung ist dem obigen Code ziemlich ähnlich (Schleife mit 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();
}
}
}
Wenn die Leistung für Ihre Software entscheidend ist, können Sie die Sprache C verwenden. Dieser Code kann 4-5 mal schneller sein als die obigen C ++ - Versionen, siehe Benchmark unten
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);
Ich habe einige Leistungsbenchmarks mit dem obigen Code durchgeführt und die Ergebnisse sind interessant. Ich habe den Code mit ASCII-Dateien getestet, die 100.000 Zeilen, 1.000.000 Zeilen und 10.000.000 Textzeilen enthalten. Jede Textzeile enthält durchschnittlich 10 Wörter. Das Programm wird mit -O3
Optimierung kompiliert und seine Ausgabe an weitergeleitet /dev/null
, um die Protokollierungszeitvariable aus der Messung zu entfernen. Zu guter Letzt protokolliert jeder Code jede Zeile mit der printf()
Funktion für Konsistenz.
Die Ergebnisse zeigen die Zeit (in ms), die jeder Code zum Lesen der Dateien benötigt hat.
Der Leistungsunterschied zwischen den beiden C ++ - Ansätzen ist minimal und sollte in der Praxis keinen Unterschied machen. Die Leistung des C-Codes macht den Benchmark beeindruckend und kann die Geschwindigkeit verändern.
10K lines 100K lines 1000K lines
Loop with std::getline() 105ms 894ms 9773ms
Boost code 106ms 968ms 9561ms
C code 23ms 243ms 2397ms
std::cout
vs printf
.
printf()
Funktion in allen Fällen aus Gründen der Konsistenz verwendet wird. Ich habe auch versucht, std::cout
in allen Fällen zu verwenden, und dies machte absolut keinen Unterschied. Wie ich gerade im Text beschrieben habe, geht die Ausgabe des Programms an, /dev/null
so dass die Zeit zum Drucken der Zeilen nicht gemessen wird.
cstdio
. Sie sollten es mit der Einstellung versucht haben std::ios_base::sync_with_stdio(false)
. Ich denke, Sie hätten viel bessere Leistungen erzielt (dies ist jedoch nicht garantiert, da es implementierungsdefiniert ist, wenn die Synchronisation ausgeschaltet ist).
Da Ihre Koordinaten paarweise zusammengehören, schreiben Sie doch eine Struktur für sie.
struct CoordinatePair
{
int x;
int y;
};
Dann können Sie einen überladenen Extraktionsoperator für istreams schreiben:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
Und dann können Sie eine Koordinatendatei direkt in einen Vektor wie diesen lesen:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
char filename[] = "coordinates.txt";
std::vector<CoordinatePair> v;
std::ifstream ifs(filename);
if (ifs) {
std::copy(std::istream_iterator<CoordinatePair>(ifs),
std::istream_iterator<CoordinatePair>(),
std::back_inserter(v));
}
else {
std::cerr << "Couldn't open " << filename << " for reading\n";
}
// Now you can work with the contents of v
}
int
Token aus dem Stream einzulesen operator>>
? Wie kann man es mit einem Backtracking-Parser zum Laufen bringen (dh wenn dies operator>>
fehlschlägt, den Stream auf die vorherige Position zurücksetzen und false oder ähnliches zurückgeben)?
int
Token zu lesen , wird der is
Stream ausgewertet false
und die Leseschleife wird an diesem Punkt beendet. Sie können dies innerhalb erkennen, operator>>
indem Sie den Rückgabewert der einzelnen Lesevorgänge überprüfen. Wenn Sie den Stream zurücksetzen möchten, würden Sie anrufen is.clear()
.
operator>>
ist es korrekter zu sagen, is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
da Sie sonst davon ausgehen, dass sich Ihr Eingabestream im Whitespace-Skipping-Modus befindet.
Erweitern der akzeptierten Antwort, wenn die Eingabe lautet:
1,NYC
2,ABQ
...
Sie können weiterhin dieselbe Logik wie folgt anwenden:
#include <fstream>
std::ifstream infile("thefile.txt");
if (infile.is_open()) {
int number;
std::string str;
char c;
while (infile >> number >> c >> str && c == ',')
std::cout << number << " " << str << "\n";
}
infile.close();
Es ist zwar nicht erforderlich, die Datei manuell zu schließen, aber es ist eine gute Idee, dies zu tun, wenn der Bereich der Dateivariablen größer ist:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Diese Antwort gilt für Visual Studio 2017 und wenn Sie aus einer Textdatei lesen möchten, welcher Speicherort relativ zu Ihrer kompilierten Konsolenanwendung ist.
Legen Sie zuerst Ihre Textdatei (in diesem Fall test.txt) in Ihrem Lösungsordner ab. Bewahren Sie die Textdatei nach dem Kompilieren mit applicationName.exe im selben Ordner auf
C: \ Benutzer \ "Benutzername" \ Quelle \ Repos \ "Lösungsname" \ "Lösungsname"
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile;
// open the file stream
inFile.open(".\\test.txt");
// check if opening a file failed
if (inFile.fail()) {
cerr << "Error opeing a file" << endl;
inFile.close();
exit(1);
}
string line;
while (getline(inFile, line))
{
cout << line << endl;
}
// close the file stream
inFile.close();
}
Dies ist eine allgemeine Lösung zum Laden von Daten in ein C ++ - Programm und verwendet die Readline-Funktion. Dies könnte für CSV-Dateien geändert werden, aber das Trennzeichen ist hier ein Leerzeichen.
int n = 5, p = 2;
int X[n][p];
ifstream myfile;
myfile.open("data.txt");
string line;
string temp = "";
int a = 0; // row index
while (getline(myfile, line)) { //while there is a line
int b = 0; // column index
for (int i = 0; i < line.size(); i++) { // for each character in rowstring
if (!isblank(line[i])) { // if it is not blank, do this
string d(1, line[i]); // convert character to string
temp.append(d); // append the two strings
} else {
X[a][b] = stod(temp); // convert string to double
temp = ""; // reset the capture
b++; // increment b cause we have a new number
}
}
X[a][b] = stod(temp);
temp = "";
a++; // onto next row
}