【问题标题】:C++ Reading data from text file into array of structuresC ++将数据从文本文件读取到结构数组中
【发布时间】:2018-11-05 02:55:26
【问题描述】:

我对 C++ 编程相当陌生,并且在将文本文件中的数据读取到结构数组中时遇到了一些麻烦。我查看了类似的帖子以尝试找到解决方案,但是,我无法使它对我有用,并想寻求一些帮助。以下是我的数据集示例(P.S. 我将使用多个不同大小的数据集):

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

下面是我的代码:

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

我想要实现的是将文本文件每行的前 5 个整数存储到“myData”结构中的“变量”数组中,然后将最后一个以空格分隔的整数存储到“分类”中变量,然后将该结构存储到数组“dataArray”中,然后移至下一行。

例如,数组中的第一个结构将包含变量 [00010],分类为 0。第二个结构将包含变量 [00011],分类为 1,依此类推。

非常感谢您对此的帮助,干杯!

【问题讨论】:

  • “非常感谢您的帮助”。不幸的是,stackoverflow.com 不是一个您可以在其中获得编程帮助的网站,这是一个问答网站,对您的问题进行非常仔细的检查时无法找到实际的、具体的问题。附: “int variables[variables];”,其中“variables”是 int,不是有效的 C++,而是编译器特定的扩展。
  • “每行的前 5 个整数”"00010" 不是 5 个整数,而是 5 个 chars 或一个整数。还有,有std::vector<>,为什么还要用new[]
  • 我建议切换到矢量,因为正如您所说,您的项目的大小可能是可变的。您还应该学习以 C++ 方式声明您的结构,而不是像在 C 中那样。如果是我,我会一次读取一行,然后将其拆分为一个字符串和 int,然后循环遍历字符串中的每个字符并推送它将整数值(char - '0')放入向量中,并将 int 分配给结构中的 int。重复,直到你用完线。使用向量的好处是您无需读取文件两次即可计算行数。
  • StackOverflow 上有 numerous similar questions 可能会帮助您入门。

标签: c++ arrays struct text-files


【解决方案1】:

为您的类型提供流提取和流插入运算符:

#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" });
}

未注释它看起来不那么可怕:

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;

}

【讨论】:

    【解决方案2】:

    看起来你正试图将二进制值保留为整数索引。如果是这种情况,它将在内部转换为整数。您可能需要再次将 int 转换为二进制。

    如果您想保留文本文件中的数据,那么您需要为索引值选择 char/string 类型。对于分类,它的值似乎是 0 或 1。因此您可以选择 bool 作为数据类型。

    #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;
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多