【问题标题】:C++ reading data from a *.txt file to vector of structC++ 从 *.txt 文件读取数据到结构向量
【发布时间】:2018-05-05 11:28:21
【问题描述】:

我是C++新手,对文件读/写有一些误解...

我有一个 .txt 数据文件,其中包含有关街道的信息,即街道、住宅号码和公寓数量

我的任务是从文件中读取数据、添加新数据、删除不需要的数据并计算某条街道上的公寓数量

为了程序工作期间的数据存储,我制作了一个结构向量:

struct homeAdressBook {
    std::string street;
    char homeNumber[255];
    int flats;
};

std::vector<homeAdressBook> HAB;

程序代码如下:

std::fstream document;
    document.open("name.txt");
    if (!document) {
        std::ofstream document;
        document.open("name.txt");
    }
    if (!document)
        std::cout << "File open error" << std::endl;
    else {
//Here (while loop) I want to read data from a file and add to my vector of struct for further usage, it partly works somehow but this point is unclear for me
        while (!document.eof()) {
            HAB.push_back(homeAdressBook());
            std::getline(document, HAB[i].street);
            document >> HAB[i].street;
            document >> HAB[i].homeNumber;
            document >> HAB[i].flats;
            i++;
        }
        document.close();
        do {
            switch (menu()) {
            case 0: {
                document.close();
                exit = false;
                break;
            }
//Here (case 1) I add new data and write it in file, here I have no problems at the moment
            case 1: {
                document.open("name.txt", std::ios::app);
                HAB.push_back(homeAdressBook());
                std::cin.ignore();
                std::cout << "Enter the address: ";
                std::getline(std::cin, HAB[i].street);
                std::cout << "Enter home number: ";
                std::cin.getline(HAB[i].homeNumber, 255);
                std::cout << "Enter number of flats: ";
                std::cin >> HAB[i].flats;
                document << HAB[i].street << HAB[i].homeNumber << HAB[i].flats << std::endl;
                document.close();
                i++;
                break;
            }
//Here (case 2) I want to read data from a file, it reads data except first line of data
            case 2: {
                int total = i;
                std::cout << std::setw(20) << "Street" << std::setw(20) << "Home Number" << std::setw(20) << "Number of flats" << std::endl;
                document.open("name.txt", std::ios::in);
                for (int j = 0; j < total; j++) {
                    std::cout << std::setw(20) << HAB[j].street << std::setw(20) << HAB[j].homeNumber << std::setw(20) << HAB[j].flats << std::endl;
                }
                document.close();
                break;
            }
//Here (case 3) data should be deleted from a file if necessary
            case 3: {
                document.open("name.txt", std::ios::out | std::ios::in);
                int strDelete = 0;
                std::cout << "0. Exit to main menu" << std::endl;
                for (i = 0; i < HAB.size(); i++) {
                    std::cout << i + 1 << ". " << HAB[i].street << std::endl;
                }
                std::cout << "\nType number of street to delete: ";
                std::cin >> strDelete;
                if (strDelete)
                    i--;
                else break;
                HAB.erase(HAB.begin() + (strDelete - 1));
                document.close();
                break;
            }
            }
        } while (exit);
    }
    system("pause");
    return 0;
}

.txt 文件中的数据是这样写的:

aaa street 10 50
aaa street 10 45
bbb street 1 10
ccc street 1 12
ccc street 1/10 25

.txt 文件中的每一行都属于结构元素的 [i]-s 向量 我无法理解在程序工作期间如何正确地将 .txt 文件中的数据添加到我的结构向量中(街道名称最多可以包含 5 或 6 个单词,以及程序如何区分它是街道名称还是街道名称)住宅号码或公寓数量)

【问题讨论】:

  • 感谢您的回答!这很有帮助,我已经尝试过这样做:unsigned int i = 0; while (document &gt;&gt; HAB[i].street &gt;&gt; HAB[i].homeNumber &gt;&gt; HAB[i].flats) { HAB.push_back(homeAdressBook()); i++; 程序给出错误:向量订阅超出范围但是如果创建另一个字符串对象并在读取期间保留数据,那么我需要使用该字符串但不需要使用向量结构
  • 读入临时变量并推回循环中的向量?
  • 我只是无法理解所有这些事情发生的逻辑我有一个包含数据的文件,带有'document >> HAB[i].street'我给出了存储信息的方式,然后我推回向量以转到另一个结构元素向量以在那里存储另一种数据......我错在哪里?
  • 但是当你这样做时,循环 HAB 的第一次迭代将是 empty 并且所有索引将 超出范围 并导致未定义的行为。您可以通过先在循环外推回来解决它,但最后您将在向量中有一个未使用的元素。

标签: c++ vector struct ifstream ofstream


【解决方案1】:

我建议你为你的结构重载operator&gt;&gt;

struct homeAdressBook
{
    std::string column1;
    std::string street;
    std::string homeAddress;
    int flats;
    friend std::istream& operator>>(std::istream& input, homeAddressBook& address);
};

std::istream& operator>>(std::istream& input, homeAddressBook& address)
{
  input >> address.column1;
  input >> address.street;
  input >> address.homeAddress;
  input >> address.flats;
  return input;
}

以上将允许您将输入过程更改为:

std::vector<homeAddressBook> database;
homeAddressBook record;
//...
std::ifstream data_file("addresses.txt");
while (data_file >> record)
{
  database.push_back(record);
}

注意事项

  1. 您的帖子描述了数据中的 3 列,但您的数据源 显示 4。
  2. 您将 document 作为输出流 (ostream) 打开并使用 getline 在输出流上。
  3. 您的结构名称包含“book”,这意味着 collection 项目。我建议使用诸如“Home_Address”之类的名称来表示 单个项目。为这本书使用std::vector

编辑 1:
operator&gt;&gt; 中的成员前缀为“地址”。

【讨论】:

  • 感谢您的回答,托马斯!但是在您声明运算符重载的地方,即 'input >> column1; input >> street ...' 当我在我的代码中使用它时,IDE 诅咒我 - column1、street、flat、homeNumber 未定义。如果我这样添加:'database[i].column1' 它没有红色下划线行,但我相信我需要声明'int i = 0'并添加'for()'循环以增加'i'......'ostream'中的'getline'怎么样(你的注释#2)它得到来自用户的行并将其附加到我的向量中,这样做是错误的吗?
  • 您可以在struct 中找到声明,即终止} 上方的行。
  • 我更正了operator&gt;&gt; 的实现,请参阅我的最新编辑。顺便说一句,您可以通过在互联网上搜索“c++ 读取文件结构空间分隔”来找到这种模式的示例。
  • 我没有使用std::getline,因为它将整个记录读入一个字符串。请记住,std::getline 是一个 input 函数,并且需要一个 std::istream 派生对象(例如,“i”前缀用于输入,例如 ifstream)。 std::getline 不适用于输出流(例如 ofstream)。字符串的operator&gt;&gt; 将读取字符,直到遇到空格。
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多