Odpowiedzi:
Najpierw wykonaj ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
Dwie standardowe metody to:
Załóżmy, że każda linia składa się z dwóch liczb i odczytuje token po tokenie:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Analiza liniowa przy użyciu strumieni ciągów:
#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)
}
Nie powinieneś mieszać (1) i (2), ponieważ parsowanie oparte na tokenach nie pożera nowych linii, więc możesz skończyć z fałszywymi pustymi liniami, jeśli użyjesz getline()
po wyodrębnieniu opartym na tokenach doszedł do końca linia już.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
konstrukcji i dotyczące obsługi błędów, zapoznaj się z tym (moim) artykułem: gehrcke.de/2011/06/… (Myślę, że nie muszę mieć złego sumienia, zamieszczając to tutaj, nawet nieco wcześniej datuje tę odpowiedź).
Służy ifstream
do odczytu danych z pliku:
std::ifstream input( "filename.ext" );
Jeśli naprawdę potrzebujesz czytać wiersz po wierszu, wykonaj następujące czynności:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Ale prawdopodobnie musisz po prostu wyodrębnić pary współrzędnych:
int x, y;
input >> x >> y;
Aktualizacja:
W swoim kodzie używasz ofstream myfile;
, jednak o
in ofstream
oznacza output
. Jeśli chcesz czytać z pliku (wejście) użyj ifstream
. Jeśli chcesz zarówno czytać, jak i pisać, użyj fstream
.
Czytanie pliku wiersz po wierszu w C ++ można wykonać na kilka różnych sposobów.
Najprostszym podejściem jest otwarcie std :: ifstream i zapętlenie za pomocą wywołań std :: getline (). Kod jest czysty i łatwy do zrozumienia.
#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();
}
Inną możliwością jest użycie biblioteki Boost, ale kod staje się bardziej szczegółowy. Wydajność jest dość podobna do powyższego kodu (Loop with 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();
}
}
}
Jeśli wydajność ma kluczowe znaczenie dla twojego oprogramowania, możesz rozważyć użycie języka C. Ten kod może być 4-5 razy szybszy niż wersje C ++ powyżej, patrz test porównawczy poniżej
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);
Z powyższym kodem przeprowadziłem kilka testów wydajności, a wyniki są interesujące. Przetestowałem kod z plikami ASCII, które zawierają 100 000 wierszy, 1 000 000 wierszy i 10 000 000 wierszy tekstu. Każdy wiersz tekstu zawiera średnio 10 słów. Program jest kompilowany z -O3
optymalizacją, a jego dane wyjściowe są przekazywane do /dev/null
w celu usunięcia zmiennej czasowej rejestrowania z pomiaru. Na koniec każdy fragment kodu rejestruje każdą linię za pomocą printf()
funkcji zapewniającej spójność.
Wyniki pokazują czas (w ms), jaki każdy fragment kodu potrzebował na odczyt plików.
Różnica w wydajności między dwoma podejściami C ++ jest minimalna i nie powinna robić żadnej różnicy w praktyce. Wydajność kodu C sprawia, że test porównawczy robi wrażenie i może być przełomem pod względem szybkości.
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()
we wszystkich przypadkach korzystać z funkcji w celu zachowania spójności. Próbowałem też używać std::cout
we wszystkich przypadkach i to absolutnie nie miało znaczenia. Jak właśnie opisałem w tekście, wyjście programu idzie do, /dev/null
więc czas drukowania linii nie jest mierzony.
cstdio
. Powinieneś spróbować z ustawieniem std::ios_base::sync_with_stdio(false)
. Sądzę, że uzyskałbyś znacznie lepszą wydajność (nie jest to jednak gwarantowane, ponieważ jest zdefiniowane w implementacji, gdy synchronizacja jest wyłączona).
Ponieważ twoje współrzędne należą do siebie jako pary, dlaczego nie napisać dla nich struktury?
struct CoordinatePair
{
int x;
int y;
};
Następnie możesz napisać przeciążony operator ekstrakcji dla istreams:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
A potem możesz odczytać plik współrzędnych prosto do wektora takiego:
#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ów ze strumienia operator>>
? W jaki sposób można sprawić, by działał z analizatorem składni cofania (tj. Gdy operator>>
zawiedzie, przywróć strumień do poprzedniej pozycji, zwróć wartość false lub coś takiego)?
int
tokenów, is
strumień oceni na, false
a pętla odczytu zakończy się w tym momencie. Możesz to wykryć operator>>
, sprawdzając wartość zwrotną poszczególnych odczytów. Jeśli chcesz wycofać strumień, zadzwoń is.clear()
.
operator>>
bardziej poprawne jest powiedzenie, is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
ponieważ w przeciwnym razie zakładasz, że twój strumień wejściowy jest w trybie pomijania białych znaków.
Rozwijanie przyjętej odpowiedzi, jeśli dane wejściowe to:
1,NYC
2,ABQ
...
nadal będziesz mógł zastosować tę samą logikę:
#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();
Chociaż nie ma potrzeby ręcznego zamykania pliku, ale warto to zrobić, jeśli zakres zmiennej pliku jest większy:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Ta odpowiedź dotyczy programu Visual Studio 2017 i jeśli chcesz czytać z pliku tekstowego, która lokalizacja jest względna w stosunku do skompilowanej aplikacji konsoli.
najpierw umieść plik tekstowy (w tym przypadku test.txt) w folderze rozwiązania. Po skompilowaniu trzymaj plik tekstowy w tym samym folderze z applicationName.exe
C: \ Users \ "nazwa użytkownika" \ source \ repos \ "nazwa rozwiązania" \ "nazwa rozwiązania"
#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();
}
Jest to ogólne rozwiązanie do ładowania danych do programu C ++ i wykorzystuje funkcję readline. Można to zmodyfikować dla plików CSV, ale separator jest tutaj spacją.
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
}