简体   繁体   中英

C++ Reading data from text file into array of structures

I am reasonably new to programming in C++ and i'm having some trouble reading data from a text file into an array of structures. I have looked around similar posts to try and find a solution however, I have been unable to make any of it work for me and wanted to ask for some help. Below is an example of my data set (PS I will be using multiple data sets of varying sizes):

00010 0
00011 1
00100 0
00101 1
00110 1
00111 0
01000 0
01001 1

Below is my code:

int variables = 5;

typedef struct {
    int variables[variables];
    int classification;
} myData;

//Get the number of rows in the file
int readData(string dataset)
{
    int numLines = 0;
    string line;
    ifstream dataFile(dataset);
    while (getline(dataFile, line))
    {
        ++numLines;
    }
    return numLines;
}

//Store data set into array of data structure
int storeData(string dataset)
{
    int numLines = readData(dataset);

    myData *dataArray = new myData[numLines];

    ...

    return 0;
}

int main()
{
    storeData("dataset.txt");

What I am trying to achieve is to store the first 5 integers of each row of the text file into the 'variables' array in the 'myData' structure and then store the last integer separated by white space into the 'classification' variable and then store that structure into the array 'dataArray' and then move onto the next row.

For example, the first structure in the array will have the variables [00010] and the classification will be 0. The second will have the variables [00011] and the classification will be 1, and so on.

I would really appreciate some help with this, cheers!

Provide stream extraction and stream insertion operators for your type:

#include <cstddef>    // std::size_t
#include <cstdlib>    // EXIT_FAILURE
#include <cctype>     // std::isspace(), std::isdigit()
#include <vector>     // std::vector<>
#include <iterator>   // std::istream_iterator<>, std::ostream_iterator<>
#include <fstream>    // std::ifstream
#include <iostream>   // std::cout, std::cerr, std::cin
#include <algorithm>  // std::copy()

constexpr std::size_t size{ 5 };

struct Data {
    int variables[size];
    int classification;
};

// stream extraction operator
std::istream& operator>>(std::istream &is, Data &data)
{
    Data temp;  // don't write directly to data since extraction might fail
               //  at any point which would leave data in an undefined state.

    int ch;  // signed integer because std::istream::peek() and ...get() return
            //  EOF when they encounter the end of the file which is usually -1.

                                                    // don't feed std::isspace
                                                   //  signed values
    while ((ch = is.peek()) != EOF && std::isspace(static_cast<unsigned>(ch)))
        is.get();  // read and discard whitespace

             // as long as
            //              +- we didn't read all variables
           //               |         +-- the input stream is in good state
          //                |         |      +-- and the character read is not EOF
         //                 |         |      |   
    for (std::size_t i{}; i < size && is && (ch = is.get()) != EOF; ++i)
        if (std::isdigit(static_cast<unsigned>(ch)))
            temp.variables[i] = ch - '0';  // if it is a digit, assign it to our temp
        else is.setstate(std::ios_base::failbit);  // else set the stream to a 
                                                  // failed state which will 
                                                 // cause the loop to end (is)

    if (!(is >> temp.classification))  // if extraction of the integer following the
        return is;                    // variables fails, exit.

    data = temp;  // everything fine, assign temp to data
    return is;
}

// stream insertion operator
std::ostream& operator<<(std::ostream &os, Data const &data)
{
    std::copy(std::begin(data.variables), std::end(data.variables),
              std::ostream_iterator<int>{ os });
    os << ' ' << data.classification;
    return os;

}

int main()
{
    char const *filename{ "test.txt" };
    std::ifstream is{ filename };

    if (!is.is_open()) {
        std::cerr << "Failed to open \"" << filename << "\" for reading :(\n\n";
        return EXIT_FAILURE;
    }

    // read from ifstream
    std::vector<Data> my_data{ std::istream_iterator<Data>{ is },
                               std::istream_iterator<Data>{} };

    // print to ostream
    std::copy(my_data.begin(), my_data.end(),
              std::ostream_iterator<Data>{ std::cout, "\n" });
}

Uncommented it looks less scary:

std::istream& operator>>(std::istream &is, Data &data)
{
    Data temp;
    int ch;

    while ((ch = is.peek()) != EOF && std::isspace(static_cast<unsigned>(ch)))
        is.get();

    for (std::size_t i{}; i < size && is && (ch = is.get()) != EOF; ++i)
        if (std::isdigit(static_cast<unsigned>(ch)))
            temp.variables[i] = ch - '0';
        else is.setstate(std::ios_base::failbit);

    if (!(is >> temp.classification))
        return is;

    data = temp;
    return is;
}

std::ostream& operator<<(std::ostream &os, Data const &data)
{
    std::copy(std::begin(data.variables), std::end(data.variables),
              std::ostream_iterator<int>{ os });
    os << ' ' << data.classification;
    return os;

}

It looks line you are trying to keep binary values as integer index. If that is the case, it will be converted into integer internally. You may need int to binary conversion again.

If you want to preserve data as is in the text file, then you need to choose either char/string type for the index value. For classification, it seems value will be either 0 or 1. So you can choose bool as data type.

#include <iostream>
#include <map>

using namespace std;

std::map<string, bool> myData;

int main()
{
    // THIS IS SAMPLE INSERT. INTRODUCE LOOP FOR INSERT.
    /*00010 0
    00011 1
    00100 0
    00101 1
    00110 1*/
    myData.insert(std::pair<string, bool>("00010", 0));
    myData.insert(std::pair<string, bool>("00011", 1));
    myData.insert(std::pair<string, bool>("00100", 0));
    myData.insert(std::pair<string, bool>("00101", 1));
    myData.insert(std::pair<string, bool>("00110", 1));

    // Display contents
    std::cout << "My Data:\n";
    std::map<string, bool>::iterator it;

    for (it=myData.begin(); it!=myData.end(); ++it)
        std::cout << it->first << " => " << it->second << '\n';

    return 0;
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM