简体   繁体   English

将文本文件中的数据存储到 C++ 以便编辑的最佳方法是什么

[英]What is the best way to store data from text file into C++ in order to Edit

I am building a Contact Management System in which I have console C++ application and I want to store contacts in a address text file like this.我正在构建一个联系人管理系统,其中有控制台 C++ 应用程序,我想将联系人存储在这样的地址文本文件中。

1
John Doe
134 main st.
south bend, IN. 38744
574-444-5554

I want to be able to store multiple contacts to the file, then read the file into memory, but not sure if I should store into an array, vector or some other data structure.我希望能够将多个联系人存储到文件中,然后将文件读入 memory,但不确定是否应该存储到数组、向量或其他一些数据结构中。

I need /want to be able to ADD, Edit, Search by Last Name, ID (1, etc..)我需要/希望能够添加、编辑、按姓氏、ID(1 等)搜索

Currently, when I put data in a text file, I can open it and read it out, but it's not stored in any organized data structure.目前,当我将数据放入文本文件时,我可以打开并读出它,但它没有存储在任何有组织的数据结构中。

Example of how I'm reading the file:我如何阅读文件的示例:

    string myText;
    // Read from the text file
    ifstream MyReadFile("address.txt");
    // Use a while loop together with the getline() function to read the file line by line
    while (getline(MyReadFile, myText)) {
        // Output the text from the file
        cout << myText << "\n";
    }
    // Close the file
    MyReadFile.close();

C++ is an object oriented language. C++ 是一种面向 object 的语言。 It helps you to abstract your real world problems into objects, consisting of data and methods, operating on this data.它可以帮助您将现实世界的问题抽象为对象,这些对象由数据和方法组成,对这些数据进行操作。

So, one of the first idea could then be to translate a "Contact" into an object. And such an object (or class) would have properties or data members that belong together and then make up a "Contact"因此,第一个想法可能是将“联系人”翻译成 object。这样的 object(或类)将具有属于一起的属性或数据成员,然后组成“联系人”

Example: You could define a class contact like this:示例:您可以像这样定义 class 联系人:

#include <string>

struct Contact {
    int ID{};
    std::string name{};
    std::string street{};
    std::string city{};
    std::string phone{};
};

With that all attributes that make up a contact, are together in on object and can be easliy handled.这样,构成联系人的所有属性都集中在 object 中,可以轻松处理。

And if you need an instance of such a Contact, you could simply write Contact c and you can easily access all data with eg c.name .如果你需要这样一个联系人的实例,你可以简单地写Contact c并且你可以轻松地访问所有数据,例如c.name

This makes life already very simple.这让生活已经很简单了。

Next.下一个。 The methods.方法。 What can you or do you want to do with ONE contact.你可以或你想用一个联系人做什么。 The only requirement that you have at the moment is, to read the data from or write them to a stream. C++ will help you also here.您目前唯一的要求是,从 stream 读取数据或将数据写入 stream。C++ 也会在这里帮助您。 You know already about the iostream facilities and that you can for example use the inserter operator << to write to any stream. It does not matter if the stream is a std::cout or any file stream or even std::ostringstream .您已经了解 iostream 设施,并且您可以例如使用插入器运算符<<写入任何 stream。stream 是std::cout还是任何文件 stream 甚至是std::ostringstream都没有关系。 It will always work.它会一直有效。

That is nice, but how to add such functionality to your "Contact" object?很好,但是如何将这样的功能添加到您的“联系人”object? This can be done be overwriting operators << and >> for your object. The class would now look like this:这可以通过为您的 object 覆盖运算符<<>>来完成。class 现在看起来像这样:

#include <iostream>
#include <string>
#include <iomanip>

struct Contact {
    int ID{};
    std::string name{};
    std::string street{};
    std::string city{};
    std::string phone{};

    friend std::istream& operator >> (std::istream& is, Contact& c) {
        is >> c.ID;
        std::getline(is >> std::ws, c.name);
        std::getline(is, c.street);
        std::getline(is, c.city);
        std::getline(is, c.phone);
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Contact& c) {
        return os << c.ID << '\n' << c.name << '\n' << c.street << '\n'
            << c.city << '\n' << c.phone << '\n';
    }
};

Now you need to think about more abstractions.现在你需要考虑更多的抽象。 You want to have not only one instance of a contact, but many of them.您不仅希望拥有一个联系人实例,而且希望拥有多个联系人实例。 And you want to work with this data, so for example, searching, adding, sorting or whatever.并且您想使用这些数据,例如搜索、添加、排序或其他任何操作。

This can of course not be done with the above object as is.这当然不能用上面的 object 原样完成。 We need to store one or many objects of it.我们需要存储它的一个或多个对象。

And for this the absolute standard approach is to use a std::vector .为此,绝对标准的方法是使用std::vector The std::vector can hold 0..many other objects and is ideally suited for your requirements. std::vector可以容纳 0..many 其他对象,非常适合您的要求。 You can write simply std::vector<Contact> contacts;您可以简单地编写std::vector<Contact> contacts; and you immediately can have many instances of "Contacts".并且您立即可以拥有许多“联系人”实例。

But in C++ you would go one step ahead.但是在 C++ 中,您将 go 领先一步。 Because you want to operate on these many "contacts", you would encapsulyte also this in a new, different object. Let us call this "Database".因为您想对这么多“联系人”进行操作,所以您也可以将其封装在一个新的、不同的 object 中。让我们称之为“数据库”。 And here you would add all functions that work with a "Contact".在这里您将添加所有与“联系人”一起使用的功能。 So, the data is a std::vector<Contact> and the mehods will operate on this data.因此,数据是一个std::vector<Contact>并且方法将对该数据进行操作。 Let us start with input and output.让我们从输入和 output 开始。

Next source code:下一个源代码:

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>

struct Contact {
    int ID{};
    std::string name{};
    std::string street{};
    std::string city{};
    std::string phone{};

    friend std::istream& operator >> (std::istream& is, Contact& c) {
        is >> c.ID;
        std::getline(is >> std::ws, c.name);
        std::getline(is, c.street);
        std::getline(is, c.city);
        std::getline(is, c.phone);
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Contact& c) {
        return os << c.ID << '\n' << c.name << '\n' << c.street << '\n'
            << c.city << '\n' << c.phone << '\n';
    }
};

struct Database {

    std::vector<Contact> data{};

    friend std::istream& operator >> (std::istream& is, Database& d) {
        d.data.clear();
        Contact tmp;
        while (is >> tmp)
            d.data.push_back(tmp);
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Database& d) {
        for (const Contact& c : d.data)
            os << c;
        return os;
    }
};

This is now already very powerful.这在现在已经很强大了。 If you have a Database d , you can output the complete database to the console with on simple statement: std::cout << d;如果你有一个Database d ,你可以使用简单的语句 output 将完整的数据库发送到控制台: std::cout << d; . . This will show all data on std::cout .这将显示std::cout上的所有数据。 And all functionionality is encapsulated in the classes.所有功能都封装在类中。 That is a big advantage.这是一个很大的优势。 Imagine that you make a modfication in the "Contact" class. The "outer" world will not be affected and continue to work without any modification.想象一下,你在“联系人”class 中进行了修改。“外部”世界不会受到影响并继续工作,无需任何修改。

Let us go now to a full example.现在让我们 go 来一个完整的例子。 For this I would like to remind you that our class is now working together with any type of stream. So, I will put some test data in a std::istringstream instead of a file.为此,我想提醒您,我们的 class 现在可以与任何类型的 stream 一起使用。因此,我将把一些测试数据放在std::istringstream而不是文件中。 Let us have a look:让我们来看看:

#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iomanip>

struct Contact {
    int ID{};
    std::string name{};
    std::string street{};
    std::string city{};
    std::string phone{};

    friend std::istream& operator >> (std::istream& is, Contact& c) {
        is >> c.ID;
        std::getline(is >> std::ws, c.name);
        std::getline(is, c.street);
        std::getline(is, c.city);
        std::getline(is, c.phone);
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Contact& c) {
        return os << c.ID << '\n' << c.name << '\n' << c.street << '\n'
            << c.city << '\n' << c.phone << '\n';
    }
};

struct Database {

    std::vector<Contact> data{};

    friend std::istream& operator >> (std::istream& is, Database& d) {
        d.data.clear();
        Contact tmp;
        while (is >> tmp)
            d.data.push_back(tmp);
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Database& d) {
        for (const Contact& c : d.data)
            os << c;
        return os;
    }
};

std::istringstream in{ R"(1
John Doe
134 main st.
south bend, IN. 38744
574-444-5554
2
Jane Doe
2 second  st.
north , IN. 5678
543-123-456
3
x y
z  st.
city
phone)" };

int main() {
    Database d{};

    in >> d;
    std::cout << d;
}

Of course you now need to add many more functions to your "Database" class. Whatever you need.当然,您现在需要向“数据库”class 添加更多功能。无论您需要什么。

And if you want to restructure the "Contact" class. Also no problem.而如果你想重组“联系人”class。也没有问题。 It will continue to work.它将继续工作。

I hope that this example gave you and idea on hiw things could be done.我希望这个例子给了你一些关于如何做事情的想法。

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

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