C++ read numbers from file and store in vectors

2019-04-15 09:49发布

问题:

I am having trouble "undoing" this method, that dumps essentially a matrix of numbers of variable size into a text file:

void vectorToFile(char *name, vector<vector<double>>* a){
    FILE* fp = fopen(name, "w");
    for(int i=0;i<a->size();i++){
        for(int j=0;j<a->at(i).size();j++){
            fprintf(fp, "%f ", a->at(i).at(j));
        }
        fprintf(fp, "\n");
    }
    fclose(fp);
}

I am having trouble implementing the reverse:

vector<vector<double>> fileToVector(char *name){ ??? }

I am guaranteed that the numbers in the file form a "rectangle", i.e. the sizes of inner vectors are all equal, but I don't know how to figure out the number of entries per row, and the number of columns.

Can anyone point me in the right direction? Every example I found so far implements something much easier, with hardcoded size, or sizes given in first row (which I cannot afford to do unfortunately)

回答1:

I'm new at C++ so I'm not sure if this is a good approach or not, but I would open the file, read in the input line by line, parsing each line as I read it. Here's some example code (untested, uncompiled):

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>

std::vector<std::vector<double> > fileToVector(const char *name)
{
    std::vector<std::vector<double> > result;
    std::ifstream input (name);
    std::string lineData;

    while(getline(input, lineData))
    {
        double d;
        std::vector<double> row;
        std::stringstream lineStream(lineData);

        while (lineStream >> d)
            row.push_back(d);

        result.push_back(row);
    }

    return result;
}


回答2:

You can try more C++ish approach:

void vectorToFile(std::vector<double> const& vec, std::string const& filename) {
    std::ofstream file(filename);
    if(file.good()) {
        file.flags(std::ios::fixed);
        std::copy(vec.begin(), vec.end(), std::ostream_iterator<double>(file));
    } else {
        // throw error or sth
    }
    file.close();
}

If you want to save as binary file, you can use ostream_binary_iterator like this one - http://bit.ly/9JAxdp:

void vectorToFile(std::vector<double> const& vec, std::string const& filename) {
    std::ofstream file(filename, std::ios::binary);
    if(file.good()) {
        file.flags(std::ios::fixed);
        std::copy(vec.begin(), vec.end(), ostream_binary_iterator<double>(file));
    } else {
        // throw error or sth
    }
    file.close();
}


回答3:

It would be easier if you used C++ I/O instead of C I/O. I'd suggest using ifstream to read in the file and use getline() to read each line. Each line is then the numbers that are supposed to go in a vector. Probably the easiest way to parse the string would be to use stringstream. You can then parse each double out and push_back() it onto the vector, so you won't have to care about the size of the vectors. I'd also suggest using std::string instead of char* wherever you can (though for file names, you generally end up having to use c_str() on the them anyway since the file I/O stuff always seems to take const char* instead of std::string).



回答4:

You can read lines, split using the separator you have, then parse to numbers. You can use getline to read lines as strings and you won't need to know the exact number.



回答5:

Is there any particular reason to use the vector > instead of using just double** and using new double[] to allocate the array and each sub-element? My guess is that the array can be dynamically resized at runtime, but if the array is allocated only once, using double** is bound to be much more efficient than iterating over a vector.

In any case, the solution to your problem is to dump the bounds of the array up-front in the file and read it back...



标签: c++ file input