Читайте файл построчно, используя ifstream в C ++ - PullRequest
550 голосов
/ 24 октября 2011

Содержимое файла file.txt:

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

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

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

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

Ответы [ 8 ]

825 голосов
/ 24 октября 2011

Сначала создайте 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() после того, как извлечение на основе токенов приведет вас к концу строки.

160 голосов
/ 24 октября 2011

Используйте 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.

32 голосов
/ 28 июля 2018

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

[Fast] Цикл с 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

Если производительность важна для вашего программного обеспечения, вы можете рассмотреть возможность использования языка Си. Этот код может быть в 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

enter image description here

11 голосов
/ 20 августа 2016

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

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
}
6 голосов
/ 18 мая 2017

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

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();
1 голос
/ 16 марта 2019

Это общее решение для загрузки данных в программу на 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
}
1 голос
/ 06 марта 2019

Этот ответ предназначен для Visual Studio 2017, и если вы хотите прочитать из текстового файла, какое расположение относительно вашего скомпилированного консольного приложения.

сначала поместите ваш текстовый файл (в данном случае test.txt) в ваше решениепапка.После компиляции сохраните текстовый файл в той же папке с applicationName.exe

C: \ Users \ "username" \ 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();
}
0 голосов
/ 01 мая 2018

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

    ifstream infile(szFilePath);

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

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