简体   繁体   English

将.txt文件读入结构数组

[英]Reading .txt file into array of struct

I'm a beginner in programming and i'm trying to read my.txt file into an array of struct in this program which after that display the data and then sort it, but the program only reads the first line and the loop won't stop until arraysize.我是编程初学者,我正在尝试将 my.txt 文件读入该程序中的结构数组,然后显示数据然后对其进行排序,但程序只读取第一行并且循环不会t 停止直到数组大小。 The file data looks like this:文件数据如下所示:

ID NAME ADDRESS AGE

The Code:编码:

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

a few comments:一些评论:

  1. for what conio lib?什么conio lib?
  2. struct (bio) start with capital letter struct (bio) 以大写字母开头
  3. don't use in char array in c++, you have string for this.不要在 c++ 的 char 数组中使用,你有这个字符串。
  4. separate the variables to separate lines (bot "char name[50], address[50];")将变量分隔为单独的行(bot“char name[50],address[50];”)
  5. better to rename members to m_X最好将成员重命名为 m_X
  6. about your "arraysize".关于你的“数组大小”。 if it const number you decide, do it with #define.如果它是您决定的 const 数字,请使用#define 来执行。 if you need the whole file, you don't need it at all.如果您需要整个文件,则根本不需要它。 (the file name too) (文件名也是)
  7. ifstream and not fstream data. ifstream 而不是 fstream 数据。 you need just read.你只需要阅读。 you don't want to change your data with some mistake.你不想因为一些错误而改变你的数据。
  8. check it the file opened well检查它的文件打开得很好
  9. in your code you check the while just before the loop.在您的代码中,您检查循环之前的 while。
  10. in your condition loop check data.good().在您的条件循环中检查 data.good()。 it check it not eof and he file is readable.它检查它不是 eof 并且他的文件是可读的。
  11. read command is for binary file读取命令用于二进制文件
  12. it's better to separate the load file and print data to 2 differents functions.最好将加载文件和打印数据分离到 2 个不同的函数中。 I didn't do it for save on your template我不是为了保存在你的模板上

Assuming the file only contains the data for the bio array (ie it doesn' have a heading at the top), you're doing too many reads here:假设文件只包含bio数组的数据(即顶部没有标题),你在这里做了太多的读取:

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

data.read() will read in a struct, so no need for data >> b[i].id etc. data.read()将读取结构,因此不需要data >> b[i].id等。

Just change the loop to:只需将循环更改为:

while (data.read((char*)&b[i], sizeof(bio)))
{
    i++;
}

to read in the data into the array element by element.将数据逐个元素读入数组中。

If, however, each bio data is on a separate line and white space separates each field refer to the other answer given by @gil.但是,如果每个生物数据都在单独的行上并且空格分隔每个字段,请参阅@gil 给出的另一个答案。

The following is maybe a little complicated for beginners, but since we are talking about C++, we should look also to a "more" objective oriented approach.以下对于初学者来说可能有点复杂,但既然我们谈论的是 C++,我们也应该寻找一种“更”面向目标的方法。

You designed a class, called bio.您设计了一个名为 bio 的 class。 In object oriented languages you will put all data for an object and also all functions that operate on this data in the class.在面向 object 的语言中,您将把 object 的所有数据以及在 class 中对该数据进行操作的所有函数放入。 So you need to add member functions.所以你需要添加成员函数。 The idea is that you encapsulate all data in an object.这个想法是将所有数据封装在 object 中。 The outside world should not know anything about the details of the class.外界应该对class的细节一无所知。 You just access it via member functions.您只需通过成员函数访问它。 And if you want to make changes later than you will do this within the member functions of the classes.如果您想稍后进行更改,您将在类的成员函数中执行此操作。 And the rest of the program will continue to work.并且程序的rest将继续工作。

Additionally we should definitely use C++ language features.此外,我们绝对应该使用 C++ 语言功能。 For examples you should use std::string for strings and not Plain old C-Style char arrays.例如,您应该将std::string用于字符串,而不是普通的旧 C 样式字符 arrays。 You should basically never use C-Style arrays in C++.您基本上不应该在 C++ 中使用 C-Style arrays。 Instead, please use STL container.相反,请使用 STL 容器。

So, then let's design a class with data members and member functions.那么,接下来让我们设计一个带有数据成员和成员函数的 class。 Since at the moment we just need input and output functionality, we overwrite the inserter and extractor operator.由于目前我们只需要输入和 output 功能,因此我们覆盖了插入器和提取器运算符。 These operators know abot the data and behaviour of the class and will take care.这些操作员了解 class 的数据和行为,并会小心处理。

See the following program:请参阅以下程序:

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

Some comments.一些评论。 On StackOverflow, I cannot use files.在 StackOverflow 上,我无法使用文件。 So in my example program, I use a std::istringstream instead.所以在我的示例程序中,我使用了std::istringstream But this is also an std::istream .但这也是一个std::istream You can use any other std::istream as well.您也可以使用任何其他std::istream So if you define an `````std::ifstream to read from a file, then it will work in the same way as the std::istringstream````.所以如果你定义一个```std::ifstream to read from a file, then it will work in the same way as the

And please see.请看。 The extractor operator does the whole work of reading the source File.提取器操作符完成读取源文件的全部工作。 It is encapsulated.它是封装的。 No outside function needs to know, how it does.没有外面的 function 需要知道,它是怎么做的。

In the main function, we define a std::vector and use its range contructor to specifiy where the data comes from.在主 function 中,我们定义了一个std::vector并使用它的范围构造函数来指定数据的来源。 We give it the std::istream_iterator , which iterates over the input data and calls the extractor operator until verything is read.我们给它std::istream_iterator ,它遍历输入数据并调用提取器运算符,直到读取所有内容。

Then we sort by names and copy the result to the output.然后我们按名称排序并将结果复制到output。

You may notice that fields in your input data are separted by space.您可能会注意到输入数据中的字段以空格分隔。 This does in general not work for none atomic data.这通常不适用于非原子数据。 The name could exist of 2 parts and the address can have a street and a city.名称可以由两部分组成,地址可以包含街道和城市。 For this CSV (Comma separated Values) files have been invented.为此,发明了 CSV(逗号分隔值)文件。

Please see a more realistic soultion below.请在下面查看更现实的灵魂。

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

We have a new source format and main is unchanged.我们有一个新的源格式,主要是不变的。 Just the extractor operator is modified.只是提取器运算符被修改。 Here we are using a different iterator to get the source data.在这里,我们使用不同的迭代器来获取源数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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