Чтение файла строка за строкой с помощью ifstream в C++

содержимое файла.txt-это:

5 3
6 4
7 1
10 5
11 6
12 3
12 4

здесь 5 3 - это пара координат. Как обрабатывать эти данные строка за строкой в C++?

Я могу получить первую строку, но как мне получить следующую строку файла?

ifstream myfile;
myfile.open ("text.txt");

7 ответов


во-первых, сделать ifstream:

#include <fstream>
std::ifstream infile("thefile.txt");

два стандартных метода:

  1. предположим, что каждая строка состоит из двух чисел и прочитать маркер, маркер:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. синтаксический анализ на основе строк, используя строковые потоки:

    #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() после извлечение на основе токенов уже привело вас к концу строки.


использовать 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.


С вашими координатами принадлежат вместе, как пары, почему бы не написать структуру для них?

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
}

расширение принятого ответа, если вход:

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

чтение файла строка за строкой в C++ может быть сделано по-разному.

[быстрый] цикл с std:: getline ()

самый простой подход-открыть std::ifstream и цикл, используя вызовы std:: getline (). Код чистый и понятный.

#include <fstream>

std::ifstream file(FILENAME);
if (file.is_open()) {
    std::string line;
    while (getline(file, line)) {
        // using printf() in all tests for consistency
        printf("%s", line.c_str());
    }
    file.close();
}

[Fast] использование Boost's file_description_source

другая возможность-использовать библиотеку 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

если производительность имеет решающее значение для вашего программного обеспечения,вы можете рассмотреть возможность использования языка C. Этот код может быть в 4-5 раз быстрее, чем версии C++ выше, см. benchmark ниже

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

Benchmark -- какой из них быстрее?

Я сделал несколько тестов производительности с кодом выше, и результаты интересны. Я протестировал код с файлами 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

enter image description here


хотя нет необходимости закрывать файл вручную, но это хорошая идея, чтобы сделать так, если область переменной файл больше:

    ifstream infile(szFilePath);

    for (string line = ""; getline(infile, line); )
    {
        //do something with the line
    }

    if(infile.is_open())
        infile.close();

с аргументами командной строки:

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include "print.h"

using namespace std;

int main (int argc, char *argv[]) 
{
    vector<string> list;
    ifstream in_stream;
    string line;
    in_stream.open(argv[1]);

    while(!in_stream.eof())
    {
        in_stream >> line;
        list.push_back(line);
    }
    in_stream.close();
    print(list);
    sort(list.begin(), list.end());
    print(list);
}