I have a file, that contain student name, id, age and number of this student. I want to read the file and for example if the number of student is 2 delete all 3 precedent lines corresponding to this student.
My txt look like this
Marc 45646564 18 1 Jean 4563213 21 2
Paul 45654 22 4 Alice 45948 20 5
while (getline(student, line))
{
if (counter % 4 == 2) { // Here I want to delete all prcedent 3 lines}
}
Unfortunately your approach, or your design idea is not that good. It should be improved a little bit.
You need to start thinking in an object-oriented way. The object "student" has properties or data elements, like "name", "id", "age" and "number". All this data belong together and are related to a specific "student". And next, you need to define methods that should operate on this data, like "reading" and "writing" the complete data for some student.
If the "number" property that you have, after reading a complete "student" record, is ok, then you will store it in some kind of array or std::vector
So, lets start with the data part:
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
};
This will describe the properties of one student.
Next, we do want to operate on this data. And the first operation is that we do want to read this data from any kind of stream, for example from the console (std::cin) or from a file (std::ifstream). This basically doesn't matter, stream is stream :-)
The iostream library has the so called "extractor" operator for reading from streams. That is the >> operator. And this we can simply define for our "Student" struct. Like so:
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
The signature of the function is given. This is a formal requirement. Then, now to what are we doing in that function. I would like to remind everybody that the istream extraction operations always return a reference to the given istream.. So, first we call std::getline. This will read the name of the student, and then return again is. Then the line looks like return is >> s.id >> s.age >> s.number. Next we will read the id. This will also return is. Then the statement would look like return is >> s.age >> s.number. And so on and so on. At the end we will have read everything and simply return is;
In the std::getline you will see >>std::ws. This will ignore all leading white spaces like new lines or whatever.
So, now, if we have an open file stream, let' s say "ifs" and a Student variable called "student", then we can write ifs >> student and it will read a complete student record from the file. So, all 4 lines.
By the way, we can do the same mechanism for the inserter function <<.
If we run this in a loop now and store the read student data into a std::vector we can copy all data from the file.
Or, if a student has a certain property, then we can also decide to not copy the data.
This could then look like:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '\n' << s.id << '\n' << s.age << '\n' << s.number << '\n';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data
std::ifstream ifs("r:\\data.txt");
// Check, if the file could be opened.
if (ifs) {
Student tempStudent{};
// Read all students from a file, until we hit eof or some other problem
while (ifs >> tempStudent) {
// if the student does fullfill the requirements, then we take it, else not
if (tempStudent.number != 2)
students.emplace_back(std::move(tempStudent));
}
// OK, for debug purposes we show all data ion the screen
for (const Student& s : students) std::cout << s << '\n';
}
else std::cerr << "\n\nError: source file could not be opened\n\n";
return 0;
}
And if you want to see a more advance C++ solution, please look at the below:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <algorithm>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '\n' << s.id << '\n' << s.age << '\n' << s.number << '\n';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data and check, if it is open
if (std::ifstream ifs("r:\\data.txt");ifs) {
// Read all data
std::copy_if(std::istream_iterator<Student>(ifs), {}, std::back_inserter(students), [](const Student& s) {return s.number != 2;});
// For debug purposes we show all data ion the screen
std::copy(students.begin(), students.end(), std::ostream_iterator<Student>(std::cout, "\n"));
}
else std::cerr << "\n\nError: source file could not be opened\n\n";
return 0;
}
Related
This question already has answers here:
std::cin input with spaces?
(8 answers)
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 8 months ago.
I'm doing a crud in C++, but in the data entry, I can't add space in the name, it bugs, I tried to use ignore and getline, it worked but the first letter disappears when reading the variable, using only getline, it doesn't work
class banca
{
private:
char name[100];
char email[100];
char course_aluno[100];
int semestre;
int id;
public:
friend istream& operator>>(istream& in, banca& p);
friend ostream& operator<<(ostream& out, banca& p);
}
istream& operator>>(istream& in, banca& p)
{
cout << "--------ALUNO--------\n";
cout << "Name: \n" << endl;
cin.ignore();
cin.getline(p.name, 100);
cout << "Email: \n";
cin.ignore();
cin.getline(p.email, 100);
cout << "Course : \n";
cin.ignore();
cin.getline(p.course_aluno, 100);
cout << "Semestre: \n";
in >> p.semestre;
cout << "ID: \n";
in >> p.id;
}
You are basically running into an old problem, when working with input functions.
You need to learn about the difference between formatted and unformatted input.
The extraction and inserter operators >> and << are formatted input functions. They read or write a sequence of characters and format them. Example:
int i = 42;
std::cout << i;
This is an example of formatted IO. Although 42 has the binary representation of 101010 you will see the character sequence "42" on the screen.
Same is valid vice versa. If you want to read a number from the user, you typically use something like
int i;
std::cin >> i;
And, although you enter the characters '4' and '2' and ENTER ('\n') in the terminal, you will get the value 42 in your variable "i". The ENTER ('\n') is still in the input stream and has not yet been consumed. This is an additional problem that I will explain in a minute.
If you want to read a string, like "Peter Parker", and use
std::string name{};
std::cin >> name;
You will only get "Peter", because the formatted input functions (per default) stop converting after they hit a white space. So, after "Peter" has been read. The whitespace will not be consumed and will be still in the input stream.
For this reason you will use std::getline to read a string. This will not stop at a whitespace, but at a delimiter, per default at '\n'. So it will read a complete line.
From reading above, you may now see the problem. If there is a transition from formatted to unformatted input there is often the problem that there is still a whitespace (often the ENTER '\n', in your case the space) in the input stream. And you need to eliminate this whitespace.
You tried it with std::ignore, but there is a better possibility: std::ws. You may read here about it. This will often be the better approach. You may use it after the transition from formatted to unformatted input the eat away the non wanted white spaces. You can also use it in general if you want to eat up leading white spaces using unformatted input. (Beware: the formatted input functions like >> will skip the white spaces (per default)).
ignore is a unformatted input function and will actively wait for characters. It is an input function. It will not return until it read something. So, be careful. It will often be just used in error cases.
With the above knowledge, we could rewrite your code like the below:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
class banca
{
private:
std::string name;
std::string email;
std::string course_aluno;
int semestre;
int id;
public:
friend std::istream& operator >>(std::istream& in, banca& p);
friend std::ostream& operator <<(std::ostream& out, const banca& p);
};
std::istream& operator>>(std::istream& in, banca& p)
{
std::cout << "\n\n--------ALUNO--------\n";
std::cout << "Name:\n";
std::getline(in >> std::ws, p.name);
std::cout << "Email:\n";
std::getline(in, p.email);
std::cout << "Course:\n";
std::getline(in, p.course_aluno);
std::cout << "Semestre:\n";
in >> p.semestre;
std::cout << "ID:\n";
in >> p.id;
return in;
}
std::ostream& operator <<(std::ostream& out, const banca& p) {
return out << "\nName:\t\t " << p.name << "\nEMail:\t\t " << p.email << "\nCourse:\t\t "
<< p.course_aluno << "\nSemestre:\t " << p.semestre << "\nID:\t\t " << p.id << '\n';
}
int main() {
banca b1,b2;
std::cin >> b1;
std::cout << b1;
std::cin >> b2;
std::cout << b2;
}
But beware. Input functions may fail. Check the return code of each input function. And if you have an error, then use ignore.
Example. If you expect a number and enter a string, then the formatted input function will fail, and all invalid characters will still be in the stream. Enter "abc" for the semester and you will see it.
Solution. Check result of IO function:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <limits>
class banca
{
private:
std::string name{};
std::string email{};
std::string course_aluno{};
int semestre{};
int id{};
public:
friend std::istream& operator >>(std::istream& in, banca& p);
friend std::ostream& operator <<(std::ostream& out, const banca& p);
};
std::istream& operator>>(std::istream& in, banca& p)
{
std::cout << "\n\n--------ALUNO--------\n";
std::cout << "Name:\n";
std::getline(in >> std::ws, p.name);
std::cout << "Email:\n";
std::getline(in, p.email);
std::cout << "Course:\n";
std::getline(in, p.course_aluno);
std::cout << "Semestre:\n";
in >> p.semestre;
std::cout << "ID:\n";
in >> p.id;
return in;
}
std::ostream& operator <<(std::ostream& out, const banca& p) {
return out << "\nName:\t\t " << p.name << "\nEMail:\t\t " << p.email << "\nCourse:\t\t "
<< p.course_aluno << "\nSemestre:\t " << p.semestre << "\nID:\t\t " << p.id << '\n';
}
int main() {
banca b1,b2;
if (std::cin >> b1)
std::cout << b1;
else {
std::cerr << "\nError: Problem with input\n\n";
std::cin.clear(); // unset failbit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // skip bad input
}
if (std::cin >> b2)
std::cout << b2;
else {
std::cerr << "\nError: Problem with input\n\n";
std::cin.clear(); // unset failbit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // skip bad input
}
}
file_name = file_name_out_of_class;
ifstream file(file_name);
if (file.is_open()) {
string line;
int temp_sap;
int temp_sem;
int temp_cours;
int temp_cred;
while (getline(file, line)) {
cout << sizeof(info) << endl;
//????????
}
}
C++
This pic contains data of the student I want to store in variables or array, but the problem is who to store it. Because 1st line contain large data and 2nd line contain small data.
Since the most important information, I mean, the column header, or field names, or student attribute is missing, I can only give a general answer.
You should abstract the data in one line into a corresponding data structure. I give you an artificial example. A line, as you did show above, could be structured like this:
First an ID, then an item, and then, 0, 1 or more pairs of Evaluators consisting of Descriptors and Numbers. All names are arbitrary chosen. If you give the descripition of the content of one line, then I could use that instead. Anyway.
Then we make an abstraction and create a datatype, a struct/class that can hold the data above.
So, first we have something like:
struct Evaluator {
std::string descriptor{};
unsigned int number{};
};
Next we make a abstraction of complete line data, maybe like that
struct Record {
unsigned int ID{};
unsigned int item{};
std::vector<Evaluator> eval{};
};
the std::vector makes the data dynamic. There can be 0,1 or more Evaluators in there.
And then we will use the C++ method of data inpit and output. The iostream facilities. You know the inserter << operator and the extractor >> operator.
This we will define for our structs.
Then the whole program will look like :
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Evaluator {
std::string descriptor{};
unsigned int number{};
// Extractor
friend std::istream& operator >> (std::istream& is, Evaluator& ev) {
return is >> ev.descriptor >> ev.number;
}
// Inserter
friend std::ostream& operator << (std::ostream& os, const Evaluator& ev) {
return os << '\t' << ev.descriptor << '\t' << ev.number;
}
};
struct Record {
unsigned int ID{};
unsigned int item{};
std::vector<Evaluator> eval{};
// Extractor
friend std::istream& operator >> (std::istream& is, Record& r) {
std::string line{};
if (std::getline(is, line)) {
std::istringstream iss(line);
// Delete old data
r.eval.clear();
// Read attributes
iss >> r.ID >> r.item;
// Read all Evaluators
Evaluator temp{};
while (iss >> temp) {
r.eval.push_back(std::move(temp));
}
}
return is;
}
// Inserter
friend std::ostream& operator << (std::ostream& os, const Record& r) {
// Write main atributes
os << r.ID << '\t' << r.item;
// Write all evaluators
for (const Evaluator& e : r.eval) os << e;
return os;
}
};
std::istringstream testFile{ R"(7001 2 OOP 4 POM 3 CS 4 Englh 3 Isl.st 2
7002 2 OOP 4 CS 4 Isl.St 2)" };
int main() {
// All records (all lines)
std::vector<Record> record;
// Read all data
Record r;
while (testFile >> r)
record.push_back(std::move(r));
// show debug output
for (const Record& rr : record) std::cout << rr << '\n';
return 0;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
The code is supposed to open an existing text file, transfer the contents into the array, then create a new text file and then write the array contents into the new text file. The problem I'm having is that the code only outputs the last line of the content from the new text file.
file.open("Patient.txt", ios::in);
while (!file.eof()) {
file >> arr[i].name >> arr[i].DOB >> arr[i].address >> arr[i].Dr_name >> arr[i].V_date;
/*cout << arr[i].name << arr[i].DOB << arr[i].address << arr[i].Dr_name << arr[i].V_date << endl;*/
}
file.close();
files.open("Patients_2.txt");
if (files.is_open()) {
for (i; i < 30; i++) {
files << arr[i].name << arr[i].DOB << arr[i].address << arr[i].Dr_name << arr[i].V_date;
}
}
files.close();
patientss.open("Patients_2.txt");
cout << "Patient 2: " << endl;
while (!patientss.eof()) {
getline(patientss, line);
cout << line << endl;
}
patientss.close();
system("pause");
return 0;
}
IMHO, you should overload the formatted insertion and extraction operators in your patient class:
struct Patient
{
std::string name;
std::string dob;
std::string address;
std::string dr_name;
std::string v_date;
friend std::istream& operator>>(std::istream& input, Patient& p);
friend std::ostream& operator<<(std::ostream& output, const Patient& p);
};
std::istream& operator>>(std::istream& input, Patient& p)
{
std::getline(input, p.name);
std::getline(input, p.dob);
std::getline(input, p.address);
std::getline(input, p.dr_name);
std::getline(input, p.v_date);
return input;
}
std::ostream& operator<<(std::ostream& output, const Patient& p)
{
output << p.name << "\n";
output << p.dob << "\n";
output << p.address << "\n";
output << p.dr_name << "\n";
output << p.v_date << "\n";
return output;
}
The above makes input and output easier:
std::vector<Patient> database;
Patient p;
while (input_file >> p)
{
database.push_back(p);
}
const unsigned int quantity = database.size();
for (unsigned int i = 0; i < quantity; ++quantity)
{
output_file << database[i];
}
The above code also supports the concepts of encapsulation and data hiding. The Patient struct is in charge or reading its members because it knows the data types of the members. The code external to the Patient is only concerned with the input and output of a Patient instance (doesn't care about the internals).
This loop has a few problems:
while (!file.eof()) {
file >> arr[i].name >> arr[i].DOB ....
You never increase i so the same arr[i] will be overwritten time and time again.
You use !file.eof() as a condition to stop reading. eof() does not get set until after you've tried to read beyond the end of the file, which means that if you had increased i as you should, the last arr would be empty / broken. Instead check if the extraction from the stream succeeded. Since the stream is returned when you do stream >> var and has an overload for explicit operator bool() const which returns !fail() you can do this check directly in your loop:
while(stream >> var) { extraction success }
Using formatted input (>>) for string fields that are likely to contain spaces is however not a good idea. Your name, nung khual, would be split so nung would go into name and khual would go into DOB. It's better to use a field separator that is very unlikely to be included in anyone's name. \n is usually good and works well with std::getline.
std::getline returns the stream that you gave as an argument which means that you can chain getlines similarly to stream >> var1 >> var2, except it's a little more verbose.
getline(getline(stream, var1), var2) will put the first line in var1 and the second line in var2.
To make input and output a little simpler you can add stream operators for your data type and make the input stream operator use getline for your fields.
Example:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct data_t {
std::string name;
std::string DOB;
std::string address;
std::string Dr_name;
std::string V_date;
};
// input stream operator using chained getlines
std::istream& operator>>(std::istream& is, data_t& d) {
using std::getline;
return getline(getline(getline(getline(getline(is,
d.name), d.DOB), d.address), d.Dr_name), d.V_date);
}
// output stream operator
std::ostream& operator<<(std::ostream& os, const data_t& d) {
return os << d.name << '\n'
<< d.DOB << '\n'
<< d.address << '\n'
<< d.Dr_name << '\n'
<< d.V_date << '\n';
}
int main() {
std::vector<data_t> arr;
if(std::ifstream file("Patient.txt"); file) {
data_t tmp;
while(file >> tmp) { // remember, no eof() needed
arr.push_back(tmp);
}
}
if(std::ofstream file("Patients_2.txt"); file) {
for(const data_t& d : arr) {
file << d;
}
}
if(std::ifstream patientss("Patients_2.txt"); patientss) {
data_t tmp;
while(patientss >> tmp) {
std::cout << tmp;
}
}
}
I am trying to understand reading different txt file formats in c++
I am currently trying to read a file formatted like this,
val1 val2 val3
val1 val2 val3
val1 val2 val3
When I read the file in and then cout its contents I only get the first line then a random 0 0 at the end.
I want to save each value into its own variable in a struct.
I am doing this like this,
struct Input{
std::string group;
float total_pay;
unsigned int quantity;
Input(std::string const& groupIn, float const& total_payIn, unsigned int const& quantityIn):
group(groupIn),
total_pay(total_payIn),
quantity(quantityIn)
{}
};
int main(){
std::ifstream infile("input.txt");
std::vector<Input> data;
std::string group;
std::string total_pay;
std::string quantity;
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
while(infile) {
data.push_back(Input(group,atof(total_pay.c_str()),atoi(quantity.c_str())));
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
}
//output
for(Input values : data) {
std::cout << values.group << " " << values.total_pay << " " << values.quantity << '\n';
}
return 0;
}
What is the proper way to read this file in the the format I have specified? Do I need to specify to go to the next line after the third value?
Or should this be taking each value and putting them in to the right variable?
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
Your input processing has a number of issues. Your prevalent usage of std::getline in places where it is not needed isn't helping.
In short, per-line validation of input is generally done with a model similar to the following. Note that this requires the class provide a default constructor. We use an input-string-stream to process a single item from each line of input from the input file. If it was certain there was at-most one per line, we could forego the per-line processing, but it is a potential place for errors, so better safe than sorry. The mantra presented here is commonly used for per-line input validation when reading a stream of objects from a formatted input file, one item per line.
The following code defines the structure as you have it with a few extra pieces, including providing both an input and output stream insertion operator. The result makes the code in main() much more manageable.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
struct Input
{
// friends not needed if the members are public, but provided here
// in case you ever do make them protected or private (which you should)
friend std::istream& operator >>(std::istream& inp, Input& item);
friend std::ostream& operator <<(std::ostream& outp, Input const& item);
std::string group;
float total_pay;
unsigned int quantity;
// default constructor. sets up zero-elements
Input() : total_pay(), quantity()
{
}
Input(std::string groupIn, float total_payIn, unsigned int quantityIn)
: group(std::move(groupIn))
, total_pay(total_payIn)
, quantity(quantityIn)
{
}
// you really should be using these for accessors
std::string const& getGroup() const { return group; }
float getTotalPay() const { return total_pay; }
unsigned int getQuantity() const { return quantity; }
};
// global free function for extracting an Input item from an input stream
std::istream& operator >>(std::istream& inp, Input& item)
{
return (inp >> item.group >> item.total_pay >> item.quantity);
}
// global operator for inserting to a stream
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
outp << item.getGroup() << ' '
<< item.getTotalPay() << ' '
<< item.getQuantity();
return outp;
}
int main()
{
std::ifstream infile("input.txt");
if (!infile)
{
std::cerr << "Failed to open input file" << '\n';
exit(EXIT_FAILURE);
}
// one line per item enforced.
std::vector<Input> data;
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
Input inp;
if (iss >> inp) // calls our extaction operator >>
data.emplace_back(inp);
else
std::cerr << "Invalid input line: " << line << '\n';
}
// dump all of them to stdout. calls our insertion operator <<
std::copy(data.begin(), data.end(),
std::ostream_iterator<Input>(std::cout,"\n"));
return 0;
}
Provided the input is properly formatted, values like this:
group total quantity
group total quantity
will parse successfully. Conversely, if this happens:
group total quantity
group quantity
group total quantity
total quantity
the extractions of the second and fourth items will fail, and appropriate warning will be issued on std::cerr. This is the reason for using the std::istringstream intermediate stream object wrapping extraction of a single line per item.
Best of luck, and I hope it helps you out.
Check this solution
It is without error checks but with conversion to types
#include<iostream>
#include<sstream>
using namespace std;
int main()
{
string line="v1 2.2 3";//lets say you read a line to this var...
string group;
float total_pay;
unsigned int quantity;
//we split the line to the 3 fields
istringstream s(line);
s>>group>>total_pay>>quantity;
//print for test
cout<<group<<endl<<total_pay<<endl<<quantity<<endl;
return 0;
}
The while loop I have while reading in from a file doesn't break. I'm not sure what the problem is. If you need any more information just ask.
Code:
#include <string>
#include <map>
#include <fstream>
#include <iostream>
#include <iterator>
using namespace std;
class Customer {
public:
string name;
string address;
Customer() {}
};
class Purchase {
public:
string product_name;
double unit_price;
int count;
Purchase() {}
Purchase(string pn, double up, int c) :product_name(pn), unit_price(up), count(c) {}
};
// Function Object for comparison in map container
struct Cmp_name {
bool operator()(const Customer& first, const Customer& second)
{ return first.name < second.name; }
};
// ostream overloads
ostream& operator<<(ostream& out, const Customer& c)
{
out << c.name << '\n'
<< c.address << '\n';
return out;
}
ostream& operator<<(ostream& out, const Purchase& p)
{
out << p.product_name << '\n'
<< p.unit_price << '\n'
<< p.count << '\n';
return out;
}
istream& operator>>(istream& in, Customer& c)
{
getline(in, c.name);
getline(in, c.address);
return in;
}
istream& operator>>(istream& in, Purchase& p)
{
getline(in, p.product_name);
in >> p.unit_price >> p.count;
return in;
}
int main()
{
cout << "Enter file to read orders from: \n";
string file;
cin >> file;
ifstream is(file.c_str());
if (!is) cerr << "File doesn't exist.\n";
multimap<Customer, Purchase, Cmp_name> orders;
while (!is.eof()) {
Customer c;
Purchase p;
is >> c;
is >> p;
orders.insert(make_pair(c,p));
}
for (multimap<Customer, Purchase, Cmp_name>::iterator it = orders.begin(); it!=orders.end(); ++it)
cout << it->first << it->second << "\n\n";
}
As for your Customer/Purchase ostream inserters, declare the second argument const& instead of non-const &. For example:
ostream& operator<<(ostream& out, Customer const& c)
That's necessary because the key in a map is immutable even if you're using a non-const iterator (modifying the key would invalidate whatever tree-sorting or hashing the map implementation uses.
It's best to check every istream extraction operation for success, and break out of the loop the first time one doesn't succeed. Your "is.eof()" isn't going to read any extra (e.g. whitespace) characters, so it may claim "!eof()" at the semantic end of file.
Something like:
for(;;) {
Customer c;
Purchase p;
if (!getline(is, c.name)) break;
if (!getline(is, c.address) break;
if (!getline(is, p.product_name) break;
if (!(is >> p.unit_price >> p.count)) break;
orders.insert(make_pair(c,p));
}
Since those all return the original istream, it's the same as having a "if (!is) break;" after every attempted input.
You can also simplify things somewhat by defining extractors for Customer and Purchase, e.g.
istream& operator>>(istream &i,Customer &c)
A failure to read a Customer would let you break out (the istream will evaluate as false if an eof stops the read from succeeding).
Obviously you can make some of the failed-input points "ok to eof" and give a specific error in all the other cases.