将.txt文件读入struct数组

时间:2019-11-20 07:00:51

标签: c++ arrays struct

我是程序设计的初学者,我试图将我的.txt文件读入该程序的结构数组中,该数组随后显示数据并对其进行排序,但该程序仅读取第一行,并且直到arraysize循环才会停止。 文件数据如下:

ID NAME ADDRESS AGE

代码:

#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;

struct bio
{
    char name[50], address[50];
    int id, age; 
};

int main() 
{   
    int i = 0, arraysize = 1000;
    bio b[arraysize];
    fstream data;
    data.open("biodata.txt");
    while(data.read((char*)&b, sizeof(b[i])))
    {
        for (i = 1; i < 1000; i++)
        {
            data >> b[i].id >> b[i].name >> b[i].address >> b[i].age;
        }
    }
    for (i = 0; i < 1000; i++)
    {
        cout << b[i].id << " " << b[i].name << " " << b[i].address << " " << b[i].age << " " << endl;
    }
    data.close();
    getch();
}

2 个答案:

答案 0 :(得分:0)

#include <iostream>
#include <fstream>
#include <string>

#define ARRAY_SIZE 1000
#define FILE_NAME "biodata.txt"

using namespace std;

struct Bio
{
    int     m_id;
    string  m_name;
    string  m_address;
    int     m_age; 
};

int main() 
{ 
    Bio bio[ARRAY_SIZE];
    ifstream data;
    data.open(FILE_NAME);

    if (!data)
    {
        cout << "not file " << FILE_NAME;
        return 0;
    }

    for (int i = 0; i < ARRAY_SIZE && data.good(); ++i)
    {
        data >> bio[i].m_id >> bio[i].m_name >> bio[i].m_address >> bio[i].m_age;
    }

    for (int i = 0; i < ARRAY_SIZE ; ++i)
    {
        cout << bio[i].m_id << " " << bio[i].m_name << " " << bio[i].m_address << " " << bio[i].m_age << " " << endl;
    }

    data.close();
}

一些评论:

  1. 用于什么conio库?
  2. 结构(生物)以大写字母开头
  3. 不要在c ++中的char数组中使用,为此您有一个字符串。
  4. 将变量分隔为单独的行(机器人“ char name [50],address [50];“])
  5. 更好地将成员重命名为m_X
  6. 关于您的“数组大小”。如果您决定使用const数字,请使用#define。如果您需要整个文件,则完全不需要。 (文件名也是如此)
  7. ifstream而不是fstream数据。您只需要阅读。您不想因某些错误而更改数据。
  8. 检查文件是否打开
  9. 在代码中,您检查循环之前的时间。
  10. 在条件循环中检查data.good()。它检查它不是eof并且文件可读。
  11. 读取命令用于二进制文件
  12. 最好将加载文件和打印数据分离为2种不同的功能。我没有这样做是为了保存在您的模板上

答案 1 :(得分:0)

对于初学者来说,以下内容可能会有些复杂,但是由于我们正在谈论C ++,因此我们也应该考虑一种“更多”的面向对象的方法。

您设计了一个名为bio的课程。在面向对象的语言中,您将把对象的所有数据以及对该数据进行操作的所有函数都放在类中。因此,您需要添加成员函数。这个想法是将所有数据封装在一个对象中。外界不应该对课程的细节一无所知。您只需通过成员函数访问它。而且,如果要晚于进行更改,则可以在类的成员函数中进行更改。该程序的其余部分将继续工作。

此外,我们绝对应该使用C ++语言功能。例如,您应该对字符串使用std::string而不是普通的老式C样式char数组。基本上,您不应该在C ++中使用C-Style数组。相反,请使用STL容器。

因此,让我们设计一个具有数据成员和成员函数的类。由于目前我们只需要输入和输出功能,因此我们将覆盖插入器和提取器运算符。这些操作员从一开始就知道该类的数据和行为,并且会注意。

请参阅以下程序:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>

struct Bio
{
    // Data
    unsigned int id{}; 
    std::string name{};
    std::string address{};
    unsigned int age{};

    // Overload extractor operator to read all data
    friend std::istream& operator >> (std::istream& is, Bio& b) {
        std::string textLine{};
        if (std::getline(is, textLine)) {
            std::istringstream textLineStream{textLine};
            textLineStream >> b.id >> b.name >> b.address >> b.age;
        }
        return is;
    }

    // Overload inserter operator to print the data 
    friend std::ostream& operator << (std::ostream& os, const Bio& b) {
        return os << b.id << " " << b.name << " " << b.address << " " << b.age;
    }
};

std::istringstream sourceFile{R"(1 John Address1 31
2 Paul Address2 32
3 Ringo Address3 33
4 George Address4 34
)"};

int main()
{
    // Define Variable and read complete source file
    std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};

    // Sort the guys by name
    std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});

    // Show output on screen
    std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));

    return 0;
}

一些评论。在StackOverflow上,我无法使用文件。因此,在示例程序中,我改用std::istringstream。但这也是std::istream。您也可以使用任何其他std::istream。因此,如果您定义`std :: ifstream to read from a file, then it will work in the same way as the std :: istringstream``。

请参阅。提取程序运算符完成读取源文件的整个工作。它被封装。没有外部功能需要知道,它是如何工作的。

在主函数中,我们定义一个std::vector并使用其范围构造器来指定数据的来源。我们给它std::istream_iterator,它会遍历输入数据并调用提取器运算符,直到读取完所有内容为止。

然后我们按名称排序,然后将结果复制到输出中。

您可能会注意到输入数据中的字段被空格隔开。这通常不适用于无原子数据。名称可以分为2部分,地址可以包含街道和城市。为此,发明了CSV(逗号分隔值)文件。

请在下面看到更现实的灵魂。

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <regex>

struct Bio
{
    // Data
    unsigned int id{}; 
    std::string name{};
    std::string address{};
    unsigned int age{};

    // Overload extractor operator to read all data
    friend std::istream& operator >> (std::istream& is, Bio& b) {
        std::string line{}; 
        std::regex re{";"};
        if (std::getline(is, line)) {
            std::vector<std::string> token{std::sregex_token_iterator(line.begin(), line.end(), re, -1), std::sregex_token_iterator()};
            if (4 == token.size()) {
                b.id = std::stoul(token[0]); 
                b.name = token[1]; 
                b.address = token[2];
                b.age = std::stoul(token[3]); 
            }
        }
        return is;
    }

    // Overload inserter operator to print the data 
    friend std::ostream& operator << (std::ostream& os, const Bio& b) {
        return os << b.id << ", " << b.name << ", " << b.address << ", " << b.age;
    }
};


std::istringstream sourceFile{R"(1; John Lenon; Street1 City1; 31
2; Paul McCartney; Street2 City2; 32
3; Ringo Starr; Street3 City3; 33
4; George Harrison; Address4; 34
)"};

int main()
{
    // Define Variable and read complete source file
    std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};

    // Sort the guys by name
    std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});

    // Show output on screen
    std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));

    return 0;
}

我们有一个新的源格式,并且main保持不变。只是提取运算符被修改。在这里,我们使用另一个迭代器来获取源数据。

相关问题