Ответы:
Сначала сделайте ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
Два стандартных метода:
Предположим, что каждая строка состоит из двух чисел и считывает токен токеном:
int a, b;
while (infile >> a >> b)
{
// process pair (a,b)
}
Разбор строк с использованием потоков строк:
#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)
}
Вы не должны смешивать (1) и (2), так как синтаксический анализ на основе токенов не сожирает новые строки, поэтому вы можете получить ложные пустые строки, если будете использовать getline()
после того, как извлечение на основе токенов привело вас к концу линия уже.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
конструкции и относительно обработки ошибок, пожалуйста, взгляните на эту (мою) статью: gehrcke.de/2011/06/… (я думаю, что мне не нужно с совестью публиковать это здесь, это даже немного предварительно даты этого ответа).
Используйте ifstream
для чтения данных из файла:
std::ifstream input( "filename.ext" );
Если вам действительно нужно читать построчно, сделайте следующее:
for( std::string line; getline( input, line ); )
{
...for each line in input...
}
Но вам, вероятно, просто нужно извлечь пары координат:
int x, y;
input >> x >> y;
Обновить:
В вашем коде вы используете ofstream myfile;
, однако o
в ofstream
означает output
. Если вы хотите прочитать из файла (вход), используйте ifstream
. Если вы хотите и читать, и писать, используйте fstream
.
Чтение файла строка за строкой в C ++ может быть сделано несколькими различными способами.
Самый простой подход - открыть std :: ifstream и цикл с использованием вызовов std :: getline (). Код чистый и понятный.
#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();
}
Другая возможность - использовать библиотеку Boost, но код становится немного более подробным. Производительность очень похожа на приведенный выше код (цикл с 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();
}
}
}
Если производительность важна для вашего программного обеспечения, вы можете рассмотреть возможность использования языка C. Этот код может быть в 4-5 раз быстрее, чем версии C ++ выше, см. Тест ниже
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);
Я сделал несколько тестов производительности с кодом выше, и результаты интересны. Я проверил код с файлами ASCII, которые содержат 100 000 строк, 1 000 000 строк и 10 000 000 строк текста. Каждая строка текста содержит в среднем 10 слов. Программа скомпилирована с -O3
оптимизацией, и ее выходные данные передаются /dev/null
, чтобы удалить переменную времени регистрации из измерения. И последнее, но не менее важное: каждый фрагмент кода регистрирует каждую строку с помощью printf()
функции согласованности.
Результаты показывают время (в мс), которое потребовалось каждому фрагменту кода для чтения файлов.
Разница в производительности между двумя подходами C ++ минимальна и не должна иметь никакого значения на практике. Производительность кода C - это то, что делает эталон впечатляющим и может повлиять на скорость игры.
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
против printf
.
printf()
функцию во всех случаях для согласованности. Я также пытался использовать std::cout
во всех случаях, и это не имело никакого значения. Как я только что описал в тексте, выходные данные программы идут /dev/null
так, что время для печати строк не измеряется.
cstdio
. Вы должны были попробовать с настройкой std::ios_base::sync_with_stdio(false)
. Я предполагаю, что вы получили бы намного лучшие результаты (хотя это не гарантировано, поскольку это определяется реализацией, когда синхронизация отключена).
Поскольку ваши координаты принадлежат парам, почему бы не написать для них структуру?
struct CoordinatePair
{
int x;
int y;
};
Затем вы можете написать перегруженный оператор извлечения для istreams:
std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
is >> coordinates.x >> coordinates.y;
return is;
}
И тогда вы можете прочитать файл координат прямо в вектор, как это:
#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
токена из потока operator>>
? Как можно заставить его работать с анализатором обратного отслеживания (т. operator>>
Е. Когда происходит сбой, откатить поток до предыдущей позиции и вернуть значение false или что-то в этом роде)?
int
токена, тогда is
поток оценивается false
и цикл чтения завершается в этой точке. Вы можете обнаружить это operator>>
, проверив возвращаемое значение отдельных чтений. Если вы хотите откатить поток, вы бы позвонили is.clear()
.
operator>>
правильнее сказать, is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
так как в противном случае вы предполагаете, что ваш входной поток находится в режиме пропуска пробелов.
Расширение на принятый ответ, если ввод:
1,NYC
2,ABQ
...
вы все равно сможете применить ту же логику, например так:
#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();
Хотя нет необходимости закрывать файл вручную, но лучше сделать это, если область действия переменной файла больше:
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
infile.close();
Этот ответ предназначен для Visual Studio 2017, и если вы хотите прочитать из текстового файла, какое расположение относительно вашего скомпилированного консольного приложения.
сначала поместите ваш текстовый файл (в данном случае test.txt) в папку вашего решения. После компиляции сохраните текстовый файл в той же папке с applicationName.exe
C: \ Users \ "Имя пользователя" \ Source \ Repos \ "solutionName" \ "solutionName"
#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();
}
Это общее решение для загрузки данных в программу на C ++ с использованием функции readline. Это может быть изменено для файлов CSV, но разделитель здесь - пробел.
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
}