c++ - 如何使用fstream c++替换文本文件中的特定值?

标签 c++ text-files ofstream

嗨,我在自动售货机上工作,我想通过更新文本文件来更新商品的数量。我一直在尝试使用ofstream和ifstream,但无法正常工作。
这是我的文本文件。

Water:1:1.99:D1
Coke:4:2.79:D2
Milk:6:3.15:D3
Ham Sandwitch:9:4.50:L1
Lunchables:3:6.00:L2
Cereal:2:3.59:L3
M&M:8:1.75:C1
SourPatch:0:2.10:C2
Twix:6:2.99:C3
这是自动售货机检查用户输入的位置,也是我要更新文件的位置
void vendingWorking(Item &item) {

if(item.quantity == 0) {
  cout << endl;
  cout << "------------------------------------" << "\n";
  cout << "" << item.name << " (OutStock)" << endl;
  cout << "------------------------------------" << "\n";
} 
else {  
  //Check if itemCode is same as product ID
  if(itemCode == item.productId) {

//HERE I WANT TO UPDATE THE QUANTITY OF THE ITEM IF USER HAS PICKED ONE
//EXAMPLE: (Old) Water:2:2.50:D1 -> (New) Water:1:2.50:D1

      //Message for user
      cout << endl;
      cout << "------------------------------------" << "\n";
      cout << "" << item.name << ", $" << fixed << setprecision(2)<< item.price << " (InStock)" << "\n" ;
      //Pass value to vector
      tempBasket.push_back({item.name, item.price});
  }
}
}

最佳答案

您想做的是:

  • 文件中读取自动售货机的产品内容
  • 以某种方式修改数据
  • 将自动售货机的产品内容写入文件

  • 修改如何工作?由于您无法使用任意新数据在线更改文件,因此需要执行以下操作:
    将文件读入内存->处理内存中的数据->将修改后的数据保存在文件中
    上面有两种方法。
  • 打开文件->读取数据->关闭文件->修改内存中的数据->打开文件以覆盖原始文件进行输出->保存数据->关闭文件

  • 或者,更安全一些:
  • 打开文件->读取数据->关闭文件->在内存中修改数据->打开临时文件以输出->将数据保存在临时文件中->关闭临时文件->如果一切正常,请删除原始文件->将临时文件重命名为原始文件名

  • 但是关键是要处理内存中的数据。
    您还可以创建“加载”和“保存”功能。因此,在任何时候,更改内存中的数据后,您都可以“保存”修改后的数据。采用上述方法之一。
    或者,您可以将数据“加载”到构造函数中,然后“保存”在析构函数中。一切随后将自动运行。
    关于“加载”功能。您需要逐行读取源文件,然后将该行拆分为所需的数据成员。我已经回答了一个问题here,它描述了关于如何分割线的4种不同方法。在下面给出的示例中,我使用基于std::regex的基于std::regex_match的解决方案。这将确保数据采用预期的格式。
    请注意,您还应该覆盖提取器和插入器运算符>><<,以便更轻松地使用流。
    最后但并非最不重要的一点是,所有内容都应封装在类中。
    请查看有效且经过测试的示例代码,了解部分实现的自动售货机功能。在这段代码中,我正在使用C++ 17功能,例如带有初始化程序的if。因此,如果要编译,请为编译器启用C++ 17。
    此外,这只是一些代码来说明上面的解释。有100万个解决方案。最后,您需要提出一些符合要求的东西。
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <iterator>
    #include <vector>
    #include <regex>
    #include <algorithm>
    #include <numeric>
    
    const std::regex re{ R"(^([^:]+):(\d+):(\d+\.\d+):([A-Z]+\d+))" };
    
    class VendingMachine {
    
        // Local definition of item struct
        struct Item {
            // Item attributes
            std::string name{};
            unsigned long quantity{};
            double price{};
            std::string productID{};
    
            // Simple overwrite of extractor operator
            friend std::istream& operator >> (std::istream& is, Item& it) {
    
                // Read a complete line and check, if that worked
                if (std::string line{}; std::getline(is, line)) {
    
                    // Check, if the input line, is in the expected format
                    if (std::smatch sm{}; std::regex_match(line, sm, re)) {
                        it.name = sm[1];
                        it.quantity = std::stoul(sm[2]);
                        it.price = std::stod(sm[3]);
                        it.productID = sm[4];
                    }
                    else std::cerr << "\n***Error while reading:  '" << line << "'\n'";
                }
                return is;
            }
            // Simple overwrite of inserter operator
            friend std::ostream& operator << (std::ostream& os, const Item& it) {
                return os << it.name << ':' << it.quantity << ':' << it.price << ':' << it.productID;
            }
        };
    
        // All products in vending machine
        std::vector<Item> products{};
    
        // Filename for saving and loading
        std::string fileName{ "products.txt" };
    
    public:
    
        // Constructor and Destructor
    
        // Constructor will load the data from a file
        VendingMachine() { load(); };                                           // Default constructor
        VendingMachine(const std::string& fn) : fileName(fn) { load(); };       // Constructor + file name
    
        // Destructor will automatically save product file
        ~VendingMachine() { save(); };
    
    
        // Simple overwrite of extractor operator
        friend std::istream& operator >> (std::istream& is, VendingMachine& vm) {
            // Delete all existing products
            vm.products.clear();
            // Copy all data from stream into internal structure
            std::copy(std::istream_iterator<Item>(is), {}, std::back_inserter(vm.products));
            return is;
        }
    
        // Simple overwrite of extractor operator
        friend std::ostream& operator << (std::ostream& os, const VendingMachine& vm) {
            // Copy all data to stream
            std::copy(vm.products.begin(), vm.products.end(), std::ostream_iterator<Item>(os, "\n"));
            return os;
        }
    
        // Load file from file
        void load() {
            // Open file and check, if it could be opened
            if (std::ifstream ifs(fileName); ifs) {
    
                // Use existing extractor operator
                ifs >> *this; 
            }
            else std::cerr << "\n***Error: Could not open file  '" << fileName << "'  for reading\n";
        }
    
        // Save products to file
        void save() {
            // Open file and check, if it could be opened
            if (std::ofstream ofs(fileName); ofs) {
    
                // Use existing inserter operator
                ofs << *this;
            }
            else std::cerr << "\n***Error: Could not open file  '" << fileName << "'  for writing\n";
        }
    
        // Show the complete content of the vending machine. Even if one product category quantity is 0
        void displayContent() {
            // Some header line
            std::cout << "\nNumber of selections in vending machine: " << products.size() << "\n\nProducts:\n\n";
            // All Items wit their attributes
            for (const Item& item : products)
                std::cout << item.productID << "\t Quantity: " << item.quantity << "\t Price: " << item.price << "\t --> " << item.name << '\n';
        }
    
        // Select an item and the decrease quatnity
        void getItem() {
            // COunt the number of overall items in the vending maschine
            const unsigned long overallItemQuantity = std::accumulate(products.begin(), products.end(), 0UL, [](size_t sum, const Item& it) {return sum + it.quantity; });
            // If there are at all products in the machine and not all item quantity is 0
            if (products.size() && overallItemQuantity > 0UL ) {
    
                // Instruction from user
                std::cout << "\n\nGet item\nPlease select from below list:\n\n";
    
                // Show list of possible selections
                for (const Item& item : products) {
                    if (item.quantity > 0UL) std::cout << item.productID << " \tPrice " << item.price << " \t--> " << item.name << '\n';
                }
    
                // Get user input. What item does the user want to have
                std::cout << "\n\nPlease select product by typing the ID: ";
                if (std::string id{}; std::getline(std::cin, id)) {
                    
                    // FInd the selected item in the product list
                    if (std::vector<Item>::iterator iter{ std::find_if(products.begin(), products.end(),[&id](const Item& i) {return i.productID == id && i.quantity > 0UL; }) };iter != products.end())
    
                        // In my example I do not handle payment. Simply decrease quantity
                        --iter->quantity;
                    else
                        std::cerr << "\n\n***Error: Unknown product ID\n"; // Wrong input
    
                }
            }
            else std::cerr << "\n\n***Error: Vending machine empty\n";
        }
    
        // Run the machine. Main menu and actions. At the moment kust get items without payment
        // Needs to be extended for real application
        void run() {
    
            // We run the main menu in a loop as long as the machine is active
            bool active{ true };
            while (active) {
    
                // Show main menu
                std::cout << "\n\n\nMain menu. Please select:\n  1 --> Get Item\n  0 --> Exit\n\nOption:   ";
    
                // Get user selection
                unsigned int option; std::cin >> option;
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    
                // Depending on the user selected action
                switch (option) {
                case 0:
    
                    // Leave function.
                    active = false;
                    std::cout << "\n\nExiting . . .\n";
                    break;
    
                case 1:
                    // Get an item
                    std::cout << "\n";
                    getItem();
                    break;
                default:
                    std::cout << "\n\n\nError: Wrong selection. Please try again\n";
                    break;
                }
            }
        }
    };
    
    
    
    int main() {
        // Define a Vending Machine. Read data from disk
        VendingMachine vendingMachine;
    
        // SHow what is in initially
        vendingMachine.displayContent();
    
        // Run the machine
        vendingMachine.run();
    
        // Show, what is now in the machine
        vendingMachine.displayContent();
    
        // Destructor of vendingMachine will be called and file automatically saved
        return 0;
    }
    

    关于c++ - 如何使用fstream c++替换文本文件中的特定值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64191607/

    相关文章:

    C++使用fstream查找特定数据

    c++ - 从文本文件打开和编辑数值数据并将结果放入新文件,C++

    text-files - 如何在谷歌驱动器中查看 C# .cs 文件?

    c - 从命令行读取文本文件 C

    PHP 每 100 行中每 10 行读取一次

    c++ - 打开一个 fstream 进行读/写(二进制)

    python - 如何在 Ubuntu 上构建 PyQt5

    python - 如何在将由 C++ 程序使用的 Python 脚本中导入 python 模块?

    c++ - 使用 Visual C++ 2008 在 C/C++ 上处理大整数

    javascript - jQuery 对 Javascript 函数的请求