[英]How replace specific value from textfile using ofstream c++?
Hi I am working an a vending machine and I want to update the quantity of the item by updating the text file.嗨,我正在使用自动售货机,我想通过更新文本文件来更新商品的数量。 I been trying using ofstream and ifstream but is not working.我一直在尝试使用 ofstream 和 ifstream 但不起作用。
This is my text file.这是我的文本文件。
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
This is where vending machine checks the user input and where i want to update the file这是自动售货机检查用户输入以及我想更新文件的地方
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});
}
}
} }
What you would like to do is:你想做的是:
How does modify somehow work?修改如何以某种方式工作? As you cannot change files online with arbitrary new data, you need to do like this:由于您无法使用任意新数据在线更改文件,因此您需要这样做:
Read file into memory --> operate on data in memory --> Save modified data in file将文件读入内存 --> 对内存中的数据进行操作 --> 将修改后的数据保存到文件中
For the above there are 2 approaches.对于上述有两种方法。
Or, a little bit safer:或者,更安全一点:
But the key is, to work on the data in memory.但关键是,要处理内存中的数据。
You can also create "load" and "save" fucntions.您还可以创建“加载”和“保存”功能。 So, at any time, after changing data in memory, you could "save" the modified data.因此,在更改内存中的数据后,您可以随时“保存”修改后的数据。 With one of the above described methods.使用上述方法之一。
Or, you could "load" your data in a constructor and "save" it in a destructor.或者,您可以在构造函数中“加载”数据并将其“保存”在析构函数中。 Everything would then work automatically.然后一切都会自动运行。
Regarding the "load" function.关于“加载”功能。 You need to read the source file line by line and then split the line into your needed data members.您需要逐行读取源文件,然后将该行拆分为所需的数据成员。 I have answered a question here , which describes 4 different methods on how to split a line.我在这里回答了一个问题,它描述了 4 种不同的分割线的方法。 In the below given example, I use a std::regex
based solution using std::regex_match
.在下面给出的示例中,我使用基于std::regex
的解决方案std::regex_match
。 This will ensure that the data is in the expected format.这将确保数据采用预期的格式。
Please note that you should also overwrite the extractor and inserter operators >>
and <<
for easier working with streams.请注意,您还应该覆盖提取器和插入器运算符>>
和<<
以便更轻松地处理流。
And last but not least, everything should be encapsulated in classes.最后但并非最不重要的一点是,一切都应该封装在类中。
Please see a working and tested example code for a partial implemented vending machine functionality.请参阅部分实现的自动售货机功能的工作和测试示例代码。 In this code I am using C++17 features, like if
with initializer.在这段代码中,我使用了 C++17 特性,比如if
with initializer。 So, If you want to compile, then please enable C++17 for your compiler.所以,如果你想编译,那么请为你的编译器启用 C++17。
Additionally, this is just some code to illustrate the explanations above.此外,这只是一些代码来说明上述解释。 There are 1 million solutions.有100万个解决方案。 In the end you need to come up with sometthing fitting the requirements.最后,您需要提出一些符合要求的东西。
#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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.