finding a string in a file using fstream in c++ - c++

This is my code
/*
Asks the user for their ID, depending on the ID depends on the results. It either goes to maintanance
or it asks the user to return DVD's or check DVD's out and changes the stock of the DVD's.
Cody Close
*/
#include <iostream>
#include <fstream>
#include <conio.h>
#include <sstream>
#include <string>
using namespace std;
void custID();
void sales();
void returns();
void discounts();
void maint();
void createAcc(string* filename, string* newID);
bool checkID(string* filename, string* search);
int main()
{
//Declares all the variables for the program
int mainID= 99959, menuChoice;
bool close = false;
bool done = false;
string vidId;
//Declares and input file and opens a file
fstream inFile;
inFile.open("dayin00.dat");
do{
do{
cout << "accountID: " << endl;
cin >> mainID;
stringstream out;
out << mainID;
mainid = out.str();
checkID("IDlist.txt", mainid);
}while(mainid.length() < 5 || mainid.length() > 9);
if(mainID!= 99959)
{
do
{
cout << "MENU:" << endl;
cout << "(1)Purchase\n(2)Return\n(3)Exit" << endl;
cin >> menuChoice;
switch(menuChoice)
{
case 1:
case 2:
case 3:
done = true;
}
}while(done == false);
}else{
maint();
}
close = true;
}while(close == false);
return 0;
}
void maint()
{
int maintChoice;
cout << "\n(1)Summary\n(2)Withdrawl\n(3)Close Down\n(4)Back to >main\n(0)Help" << endl;
cin >> maintChoice;
switch (maintChoice)
{
case 1:
case 2:
case 3:
case 4:
default:
cout << "1 for summary, 2 for withdrawl, 3 to close down, 4 to >go back to main" << endl;
}
}
void createAcc(string* filename, string* newID)
{
fstream newFile;
newFile.open(filename);
newFile << newID;
}
void checkID(string* filename, string* ID)
{
fstream infile;
infile.open("IDlist.txt");
string word;
infile >> word;
while (!infile.eof()){
if(word == ID)
{
cout << "ID FOUND!" << endl;
}else{
createAcc(infile, ID);
}
}
}
The text file only contains the ID 99959. How do I check if the ID the user types in already exists in the text file and if it doesn't, then it goes to createAcc(),setting up a new account using the ID that the user has entered.

The code opens file with users ID in read mode, reads it line by line and tries to finde ID. If ID not found in file, it opens file in write mode and add user ID in file.
#include <iostream>
#include <fstream>
#include <stdexcept>
void createAcc(const std::string& filename, const std::string& id)
{
std::ofstream os(filename);
if (os)
os << id;
else
throw std::runtime_error("Open file error: " + filename);
}
bool isStringContainsID(const std::string& line, const std::string& id)
{
if (line.find(id) == std::string::npos)
return false;
else
return true;
}
bool isFileContainsID(const std::string& filename, const std::string& id)
{
std::ifstream is(filename);
if (!is)
throw std::runtime_error("Open file error: " + filename);
std::string line;
while (is)
{
std::getline(is, line);
if (isStringContainsID(line, id))
return true;
}
return false;
}
int main() {
std::string id("99959");
std::string file_name("IDlist.txt");
if (isFileContainsID(file_name, id))
std::cout << "ID FOUND!" << std::endl;
else
createAcc(file_name, id);
return 0;
}
Note that all users ID should have the same length in string representation, otherwise the code can find shorter ID in file that contains larger ID with shorter ID as sub-string.

Related

read and write from files or from cin and cout

my code work good when the argc is 1 but when I try to read and write from files (when argc is 3)
the program not working well. Gcalc get the ostream (output file or cout) and current line in input file
or cin and decode the string to command on gcalc data.
#include <ostream>
#include <fstream>
#include <string>
#include <iostream>
#include "Gcalc.h"
using namespace std;
int main(int argc, char* argv[]) {
Gcalc gcalc;
string current_line;
ifstream input;
ofstream output;
if (argc != 1 && argc != 3) {
return 0;
}
if (argc == 3) {
input = ifstream(argv[1]);
cin.rdbuf(input.rdbuf());
output = ofstream(argv[2]);
cout.rdbuf(output.rdbuf());
}
while (cin.good()) {
if (argc == 1) {
cout << "Gcalc> ";
}
getline(cin, current_line);
try {
gcalc.implementCommand(cout, current_line);
}
catch (Quit_Program& error) {
break;
}
catch (std::bad_alloc& error) {
std::cerr << "Error: fatal error - bad allocation" << endl;
break;
}
catch (Exception& error) {
cout << error.what() << endl;
}
}
return 0;
}
Check that opening the files was done successfully.
Check that the istream you read from doesn't have the failbit set after you've read from it. Since an istream in a boolean context checks badbit and failbit and that std::getline returns the same istream you gave it, replace your while (cin.good()) with:
while(getline(cin, current_line)) {
// ... only entered if badbit and failbit are false ...
}
That said, it's usually better to create a separate function for reading/writing to generic istream/ostreams. This way you don't have to mess with the rdbufs of cin and cout.
#include <fstream>
#include <iostream>
#include <string>
#include "Gcalc.h"
void do_stuff(std::istream& is, std::ostream& os) {
Gcalc gcalc;
std::string current_line;
while(getline(is, current_line)) {
try {
gcalc.implementCommand(os, current_line);
} catch(Quit_Program& error) {
break;
} catch(const std::bad_alloc& error) {
std::cerr << "Error: fatal error - " << error.what() << std::endl;
break;
} catch(Exception& error) {
std::cout << error.what() << std::endl;
// or, if you really want it:
// os << error.what() << std::endl;
}
}
}
int main(int argc, char* argv[]) {
if(argc == 1) {
do_stuff(std::cin, std::cout);
} else if(argc == 3) {
std::ifstream input(argv[1]);
std::ofstream output(argv[2]);
if(input && output) do_stuff(input, output);
}
}
If you want to give the user a prompt when the program is running in interactive mode, you could add a function that prints the prompt and then calls std::getline. You can combine this inside the while loop, but it looks messy, so I would suggest something like this:
std::istream& prompt(std::istream& is, std::string& line) {
if(&is == &std::cin) std::cout << "Gcalc> ";
return std::getline(is, line);
}
// ...
while(prompt(is, current_line)) {
// ...
}

failbit getting set with ifstream object, what can be the cause?

I have written a small C++ program to set a property in a text file. The implementation is as following:
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
const string PROPFILE = "./propfile";
const string TEMPFILE = PROPFILE + ".tmp";
int setProp(const string &key, const string &val) {
try {
ifstream original(PROPFILE, ios::in);
ofstream tempfile(TEMPFILE, ios::out | ios::trunc);
for (string line; getline(original, line); ) {
if (line.compare(0, key.size(), key) == 0 && line[key.size()] == '=') {
tempfile << key << '=' << val << endl;
} else {
tempfile << line << endl;
}
}
cout << "original.rdstate()" << original.rdstate() << endl;
original.close();
tempfile.close();
} catch (ifstream::failure e) {
cerr << e.what() << endl;
}
if (rename(TEMPFILE.c_str(), PROPFILE.c_str()) != 0) {
cout << "Could not move " + TEMPFILE << "to " << PROPFILE << endl;
return 1;
}
return 0;
}
int main(int argc, const char *argv[]) {
try {
return setProp(argv[1], argv[2]);
} catch (logic_error) {
cout << "Invalid args" << endl;
return 1;
}
}
However, when I try to compile and execute it from commandline via ./a.out TESTPROP TESTVALUE, the value IS set as expected in propfile but rdstate() returns 6 (which means failbit and eofbit are set), I can't understand why are they getting set, can somebody explain ?
Contents of propfile before running ./a.out TESTPROP TESTVALUE are:
TESTPROP=NOTHING
After running the progam:
TESTPROP=TESTVALUE
I'm just a student, please don't mind if it's a dumb question :)
This is expected behaviour, the failbit is set whenever there is a failure to read the expected value. Even if that failure is because of end of file.
For instance see here
If no characters were extracted for whatever reason (not even the
discarded delimiter), getline sets failbit and returns.

is there an example of protobuf with text output?

I want to use protobuf and to create the serialization output file in text format for testing and for a replacement of json. I can't figure out how to write it on my own and am looking for examples.
Here is the one on binary output :
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_people());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
Can I just do some minor changes in this one to output in text format or something else needs to be done? Please either suggest the changes required or any link where code exists (in any language).
The debug string output is guaranteed to be valid text-serialized format, but does not care about whether the protocol message is actually valid:
std::string s = msg.DebugString(); // or ShortDebugString
If you want to validate, use TextFormat::PrintToString:
#include <google/protobuf/text_format.h>
if (std::string s; google::protobuf::TextFormat::PrintToString(msg, &s)) {
std::cout << "Your message: " << s;
} else {
std::cerr << "Message not valid (partial content: "
<< msg.ShortDebugString() << ")\n";
}
Tools for JSON interop are available in json_util.h.
This code will serialise protobuf messages to JSON and deserialise JSON to protobuf messages.
This is lifted straight out of production code (which I own and hereby grant you licence to use, but please credit me).
This is linked against protobuf 3.
Header:
struct pretty_json_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.add_whitespace = true;
}
};
static constexpr pretty_json_type pretty_json{};
struct compact_json_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.add_whitespace = false;
}
};
static constexpr compact_json_type compact_json{};
struct include_defaults_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.always_print_primitive_fields = true;
}
};
static constexpr include_defaults_type include_defaults{};
template<class...Options>
auto json_options(Options&&...options)
{
google::protobuf::util::JsonOptions opts;
using expand = int [];
void(expand{
0,
((options(opts)),0)...
});
return opts;
}
std::string as_json(const google::protobuf::Message& msg,
google::protobuf::util::JsonOptions opts = json_options(pretty_json,
include_defaults));
std::string as_json(const google::protobuf::Message* msg,
google::protobuf::util::JsonOptions opts = json_options(pretty_json,
include_defaults));
google::protobuf::Message& from_json(google::protobuf::Message& msg,
const char* first,
std::size_t size);
inline
decltype(auto) from_json(google::protobuf::Message& msg,
const std::string& json)
{
return from_json(msg, json.data(), json.length());
}
Implementation
std::string as_json(const google::protobuf::Message& msg,
google::protobuf::util::JsonOptions opts)
{
namespace pb = google::protobuf;
namespace pbu = google::protobuf::util;
auto buffer = msg.SerializeAsString();
std::string result;
pb::io::ArrayInputStream zistream(buffer.data(), buffer.size());
auto resolver = std::unique_ptr<pbu::TypeResolver> {
pbu::NewTypeResolverForDescriptorPool("",
pb::DescriptorPool::generated_pool())
};
auto status = google::protobuf::util::BinaryToJsonString(resolver.get(),
"/" + msg.GetDescriptor()->full_name(),
buffer,
std::addressof(result),
opts);
if (!status.ok())
{
std::ostringstream ss;
ss << status;
throw std::runtime_error(ss.str());
}
return result;
}
std::string as_json(const google::protobuf::Message* msg,
google::protobuf::util::JsonOptions opts)
{
return as_json(*msg, opts);
}
google::protobuf::Message& from_json(google::protobuf::Message& msg,
const char* first,
std::size_t size)
{
namespace pb = google::protobuf;
namespace pbu = google::protobuf::util;
auto resolver = std::unique_ptr<pbu::TypeResolver> {
pbu::NewTypeResolverForDescriptorPool("", pb::DescriptorPool::generated_pool())
};
auto zistream = std::make_unique<pb::io::ArrayInputStream>(first,
size);
auto binary_buffer = std::string {};
binary_buffer.reserve(size);
auto zostream = std::make_unique<pb::io::StringOutputStream>(std::addressof(binary_buffer));
auto status = pbu::JsonToBinaryStream(resolver.get(),
"/" + msg.GetDescriptor()->full_name(),
zistream.get(), zostream.get());
zistream.reset();
zostream.reset();
if (msg.ParseFromString(binary_buffer))
{
return msg;
}
throw std::runtime_error("invalid message");
}
To convert a message to JSON in three lines of code, do this -
#include <google/protobuf/util/json_util.h>
static std::string ProtoToJson(const google::protobuf::Message& proto)
{
std::string json;
google::protobuf::util::MessageToJsonString(proto, &json);
return json;
}

How to append to one file, then copy said file into another file

I feel like I've tried everything, I can get the first file to append to the second but cannot get the second file into a third. What am I doing wrong?
To be clear I need to take one file, append it to a second file, then put the contents of that second file into a third. I was able to simulate this outcome by putting both files into strings and then putting those strings into a third file, but that's not 'correct' in this problem.
I'm not particular to any way or any technique, I've tried a few and nothing works. This is the latest attempt, still doesn't work for the last step.
Here's my code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string a,b,c;
cout << "Enter 3 file names: ";
cin >> a >> b >> c;
fstream inf;
ifstream two;
fstream outf;
string content = "";
string line = "";
int i;
string ch;
inf.open(a, ios::in | ios:: out | ios::app);
two.open(b);
outf.open(c, ios::in);
//check for errors
if (!inf)
{
cerr << "Error opening file" << endl;
exit(1);
}
if (!two)
{
cerr << "Error opening file" << endl;
exit(1);
}
if (!outf)
{
cerr << "Error opening file" << endl;
exit(1);
}
for(i=0; two.eof() != true; i++)
content += two.get();
i--;
content.erase(content.end()-1);
two.close();
inf << content;
inf.clear();
inf.swap(outf);
outf.close();
inf.close();
return 0;
Here's an idea:
#include <fstream>
using namespace std;
void appendf( const char* d, const char* s )
{
ofstream os( d, ios::app );
if ( ! os )
throw "could not open destination";
ifstream is( s );
if ( ! is )
throw "could not open source";
os << is.rdbuf();
}
int main()
{
try
{
appendf( "out.txt", "1.txt" );
return 0;
}
catch ( const char* x )
{
cout << x;
return -1;
}
}

Passing a file into a function

I'm trying to create a program that passes a file to a function. The function is supposed to detect how many lines are in my file. I don't think I'm passing the file correctly into my function, I've tried several different ways. Any help will be greatly appreciated.
#include <iostream>
#include <fstream>
#define die(errmsg) {cerr << errmsg << endl; exit(1);}
using namespace std;
int num_of_lines(ifstream file)
{
int cnt3;
string str;
while(getline(file, str))cnt3++;
return(cnt3);
}
int main(int argc, char **argv)
{
int num_of_lines(ifstream file);
string file;
file = argv[1];
if(argc == 1)die("usage: mywc your_file"); //for some reason not working
ifstream ifs;
ifs.open(file);
if(ifs.is_open())
{
int a;
cout << "File was opened\n";
a = num_of_lines(file);
cout <<"Lines: " << a << endl;
}
else
{
cerr <<"Could not open: " << file << endl;
exit(1);
}
ifs.close();
return(0);
}
Two problems with the function. First, you should pass the stream by reference. Second, you just forgot to initialise your counter.
int num_of_lines( ifstream &file )
{
int cnt3 = 0;
string str;
while( getline(file, str) ) cnt3++;
return cnt3;
}
The other thing is you're passing file to it (which is a string) instead of ifs. Change the call to:
a = num_of_lines( ifs );