0

I have written a function that reads an unknown number of data (when in a column) from a file to a vector.

#include <iostream>
#include <vector>
#include <fstream> // file writing
#include <cassert>


void ReadFromFile(std::vector<double> &x, const std::string &file_name)
{
    std::ifstream read_file(file_name);
    assert(read_file.is_open());

    size_t lineCount = 0;
    while (!read_file.eof())
    {
        double temp;
        read_file >> temp;
        x.at(lineCount) = temp;
        if (lineCount == x.size() - 1) { break; } // fixes the out of range exception

        lineCount++;
    }
    read_file.close();
}
int main()
{
    size_t Nx = 7;
    size_t Ny = 7;
    size_t Nz = 7;
    size_t N = Nx*Ny*Nz;

    // Initial Arrays 
    std::vector <double> rx(N);
    std::string Loadrx = "Loadrx.txt";
    ReadFromFile(rx, Loadrx);
}

But the lineCount is incrementing one extra time after the data from the file have been copied into the vector. Is there a more elegant way of fixing that problem than the if statement that I have written?

EDIT: Obviously, I will not upload the data file. The code compiles perfectly I am just looking for an improvement in the if statement (if one exists).

nikjohn
  • 575
  • 11
  • 20
  • Use getline() instead. – xtluo Nov 18 '16 at 03:57
  • Use x.push_back() instead of x.at(linecount), pass N direct to ReadFromFile, construct v but leave empty, and reserve N elements. – 2785528 Nov 18 '16 at 04:09
  • @nikjohn you do realize that edits are tracked. The original question did not compile. Nice try. – Matt Nov 18 '16 at 04:20
  • @Matt you do realise the error was in the main, which was irrelevant, since I simply asked for an improvement of the logic of the if statement in the void function. Also, the you do realise that the code would not compile independently of that since to data file was not provided. – nikjohn Nov 18 '16 at 04:31
  • These examples might be helpful: http://stackoverflow.com/documentation/c%2b%2b/7660/iostream-library#t=201611180446580050485 – Sergey Nov 18 '16 at 04:46

2 Answers2

6

I have written a function that reads an unknown number of data (when in a column) from a file to a vector.

One of the most elegant (and, I suppose, idiomatic) ways to read unknown amount of data from a "column" (or otherwise regularly-formatted) file is to use istream iterators:

void ReadFromFile(std::vector<double> &x, const std::string &file_name)
{
    std::ifstream read_file(file_name);
    assert(read_file.is_open());

    std::copy(std::istream_iterator<double>(read_file), std::istream_iterator<double>(),
        std::back_inserter(x));

    read_file.close();
}

Usage:

int main()
{
    // Note the default constructor - we are constructing an initially empty vector.
    std::vector<double> rx;
    ReadFromFile(rx, "Loadrx.txt");
}

If you want to write a "safe" version with a limited number of elements to read, use copy_if:

void ReadFromFile(std::vector<double> &x, const std::string &file_name, unsigned int max_read)
{
    std::ifstream read_file(file_name);
    assert(read_file.is_open());

    unsigned int cur = 0;
    std::copy_if(std::istream_iterator<double>(read_file), std::istream_iterator<double>(),
    std::back_inserter(x), [&](const double&) {
        return (cur++ < max_read);
    });

    read_file.close();
}

Usage is obvious:

ReadFromFile(rx, Loadrx, max_numbers);
Sergey
  • 7,777
  • 4
  • 42
  • 76
  • Maybe, it could be optimized by 'reserving' the vector size in advance, based on the file size? Like in https://stackoverflow.com/questions/15138353/how-to-read-a-binary-file-into-a-vector-of-unsigned-chars – ferdymercury Aug 11 '20 at 11:03
0

Try:

void ReadFromFile(const size_t N, 
                  std::vector<double> &x, 
                  const std::string &file_name)
{
    std::ifstream read_file(file_name);
    assert(read_file.is_open());

    while (true)
    {
        double temp;
        read_file >> temp;  // read something

        if(read_file.eof()) break; // exit when eof

        x.push_back(temp);    
        if (N == x.size()) break;  // exit when N elements
    }
    read_file.close();
}

int main()
{
    size_t N = 10;
    std::vector<double> v;
    v.reserve(N);
    ReadFromFile(v,"Data.txt");
}
2785528
  • 5,360
  • 2
  • 17
  • 19