Please help me with file I/O

Hello there, I am working on an assignment and the instruction is below.


This fifth assignment will allow you to better explore the concept of File I/O within the C++ programming language.
For this assignment, you are going to read-in (using C++ File I/O) the contents of a text file (.txt) and calculate the letter grade for a given student based upon weighted averages and write this out to a text file (.txt). We will use the weights as outlined in the Syllabus for this course: Assignments: 50%, Participation: 10%, Midterm Exam: 20%, Final Exam: 20%. Your program should read-in the grade category and then each of the respective scores separated/delimited by a comma.
Once you have finished reading the contents of the file you will need to invoke a function, calculateLetterGrade, that has a return type of void and two parameters: one of type double with By-Value semantics and the other of type char with By-Reference semantics. Your program should then write this calculated grade to another user specified text file (.txt) before terminating. You are expected to check to ensure that each respective file opens and that you properly close your file(s).



Here is my code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  #include <iostream>
#include <fstream>
#include <string>
void calculateLetterGrade(double score, char &grade);

int main(){

   std::string fileName("");
   char grade;
   double totalScore(0);

   std::cout << "Welcome to the great Grade Calculator!" << std::endl;
   
   std::cout << "Please enter the file you wish to open: ";
   std::cin >> fileName;

   // open file to read
   std::ifstream file(fileName);
   
   //display the file on the console
   if(file.is_open())
   {
   	   std::cout << "Reading from file " << fileName << "...\n";
	   std::cout << "Here is your file " << std::endl;
	   
	   while(std::getline(file, fileName))
   	   {
	   		std::cout << fileName << std::endl;	
	   }
   }
   else
   {
		std::cout << "Unable to open file. " << std::endl;	
   }
		

   // loop upto end of file
   while(!file.eof())
   {
       // read type
       std::string gradeCategory("");
       file >> gradeCategory; //stream extraction

       // assign the weight in each category
       double weight(0);

       if(gradeCategory == "Assignments")
	   {
           weight = 0.5; //50%
       }
       else if(gradeCategory == "Participation")
	   {
           weight = 0.1; //10%
       }
       else if(gradeCategory == "Midterm" || gradeCategory == "Final")
	   {
           weight = 0.2; //20%
       }

	   double total(0), count(0);
	   
       // read count of scores for type
       file >> count;

       // loop for count times
       for(int i = 0; i < count; i++)
	   {
           // read score and add to total
           double score;
           file >> score;
           total = total+score;
       }
	   
       // calculate average and add weighted score to totalScore
       double average = total/count;
       totalScore = totalScore+(average*weight);
	   
   } 
   
   // close file
   file.close();

   // call function to get grade
   std::cout << "Calculating grades...\n";
   calculateLetterGrade(totalScore,grade);

   // read output filename and open it
   std::cout << "Save To (Filename): ";
   std::cin >> fileName;

   std::ofstream fileForGrade(fileName);

   // write score to file 
   fileForGrade << totalScore;

   // write grade to file and then close file
   fileForGrade << grade;

   fileForGrade.close();

   std::cout << "Score & Letter Grade written to file: " << fileName << std::endl;

   std::cout << "Thank you for using my program, have a bless day!" << std::endl;

   return 0;
}

// function to calculate grade by give score
void calculateLetterGrade(double score, char &grade){
   // assign 'A' if score greater than or equal to 90
   if(score>=90){
       grade = 'A';
   }
   // assign 'B' if score greater than or equal to 80
   else if(score>=80){
       grade = 'B';
   }
   // assign 'C' if score greater than or equal to 70
   else if(score>=70){
       grade = 'C';
   }
   // assign 'D' if score greater than or equal to 60
   else if(score>=60){
       grade = 'D';
   }
   // assign 'F', means fail
   else{
       grade = 'F';
   }
}


Everything compiles and run but for the output file I get 0. Can anyone point out what I did wrong?
Loop on lines 26-29 reads everything from the input file. You should be at EOF by line 38 ...
Hello nhantrivo,

When I run your program I get this:

 Welcome to the great Grade Calculator!

 Please enter the file you wish to open:


Now I have 2 problems:
1. At this point I have no idea what file(s) are available to open.

2. I have no input file to use or any idea what to put into it.

You need to provide the input file. If it is a large file then a good sample will do.

Not knowing what the input file looks like lines 21 - 34 make no sense.

Even if line 38 would be true the loop condition would loop 1 more time than you need to because you would set "eof" after you check for "eof". while (file >> gradeCategory) would be the best way to read a file of unknown length, but even that may not work depending on the input file.

You really need to post the input file so everyone can see what you are working with.

On lines 8 and 41 you do not have to initialize a "std::string". It is empty when defined and has no size.

On line 15 using "std::getline()" would be a better choice in case the file name has a space.

Be careful with file.is_open(). Just because the file is open may not mean the file is usable.

Line 26 uses the variable "fileName". This will over write the original file name you entered on line 15, so if you would need that later you no longer have it.

I offer this as a suggestion:
1
2
3
4
5
6
7
8
9
10
11
const std::string inFileName{ "" };  // <--- Put File name here.

std::ifstream inFile(inFileName);

if (!inFile)
{
    std::cout << "\n File " << std::quoted(inFileName) < " did not open.\n";
    //std::cout << "\n File \"" << inFileName << "\" did not open.\n";

    return 1;
}

If there is a problem you leave the program because there is no point in continuing. The "!inFile" check for more than just being open.

For line in your case std::string inFileName; to let the user enter a name.

That is what I see for the moment. I will let you know if I find more.

Andy
Hello Andy,

Sorry I didn't put all of the information out. the input file is named "grade.txt"
with the information below

Assignments
75,86,90,80,95,100
Participation
90
Midterm
75
Final
90

I think I got it figured out though, here is my updated code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void calculateLetterGrade(double score, char &grade);

int main(){

   std::string fileName("");
   char grade;
   double totalScore(0);

   std::cout << "Welcome to the great Grade Calculator!" << std::endl;
   
   std::cout << "Please enter the file you wish to open: ";
   std::cin >> fileName;

   // open file to read
   std::ifstream file(fileName);
   
   //display the file on the console
   if(file.is_open())
   {
   	   std::cout << "Reading from file " << fileName << "...\n";
	   
	   std::string line;
	   while (std::getline(file, line))
	   {
	       // assign the weight in each category
	       std::string gradeCategory = line;
	       double weight(0.0);

	       if (gradeCategory == "Assignments")
	       {
	           weight = 0.5; //50%
	       }
	       else if (gradeCategory == "Participation")
	       {
	           weight = 0.1; //10%
	       }
	       else if (gradeCategory == "Midterm" || gradeCategory == "Final")
	       {
	           weight = 0.2; //20%
	       }
           
	       // read scores in each category and add to total
	       std::getline(file, line);
	       std::istringstream iss(line);
	       double score(0.0), total(0.0); 
	       int count(0);
	       char comma;

	       while (iss >> score)
	       {
	           total += score;
	           ++count;
	           iss >> comma;
	       }

	       if (count != 0)
	       {
	           // calculate average and add weighted score to totalScore
	           double average = total / count;
	           totalScore += (average * weight);
	       }
	   }
   }
   else
   {
		std::cout << "Unable to open file. " << std::endl;	
   }
		

   // close file
   file.close();

   // call function to get grade
   std::cout << "Calculating grades...\n";
   calculateLetterGrade(totalScore,grade);

   // read output filename and open it
   std::cout << "Save To (Filename): ";
   std::cin >> fileName;

   std::ofstream fileForGrade(fileName);

   // write score to file 
   fileForGrade << totalScore;

   // write grade to file and then close file
   fileForGrade << " " << grade;

   fileForGrade.close();

   std::cout << "Score & Letter Grade written to file: " << fileName << std::endl;

   std::cout << "Thank you for using my program, have a bless day!" << std::endl;

   return 0;
}

// function to calculate grade by give score
void calculateLetterGrade(double score, char &grade){
   // assign 'A' if score greater than or equal to 90
   if(score>=90){
       grade = 'A';
   }
   // assign 'B' if score greater than or equal to 80
   else if(score>=80){
       grade = 'B';
   }
   // assign 'C' if score greater than or equal to 70
   else if(score>=70){
       grade = 'C';
   }
   // assign 'D' if score greater than or equal to 60
   else if(score>=60){
       grade = 'D';
   }
   // assign 'F', means fail
   else{
       grade = 'F';
   }
}

It compiles and write to output file exactly what I wanted to do. Thank you very much for your feedbacks!
Hello nhantrivo,

Line 19 should at least be followed with the if statement I showed you. If the file does not open you need to leave the program at that point. If the file did not open you would go to the else part and after you print the message you would continue with closing a file stream that is not open. Not sure what would happen.

Then you would continue with line 78 as if nothing is wrong, but the rest of you code would not work very well.

You define: std::string fileName("");. This may work, but the ("") has no affect on the string it is still empty and has (0)zero size just as if you wrote: std::string fileName;. They both end up exactly the same.

Somebody must be teaching something old because I have not seen () used to initialize a variable for long time. From the 2011 standards on the {}s are the more preferred way to initialize variables.

With the exception of "std::strings" and other containers like "vector"s you should initialize all your variables when defined.

In the "calculateLetterGrade" function you have: if(score>=90). This may work, but you are comparing a double to an int. Aside from the warning that the compiler should give comparing a double to an int may not always come out the way that you want.

Line 85 opens the output file stream. You still need to check it is open and working. Just because an output file will be created if it does not exist there are still other reasons for an output not to open.

That is what I see for now before I give the code a test.

Andy
Thank you Andy for all of your feedbacks, its helping me a lot building from foundation. I wish I can buy you a beer!
Perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

char calculateLetterGrade(double score);

int main()
{
	std::string ifileName {"grades.txt"};
	std::string ofileName {"grades.out"};

	std::cout << "Welcome to the great Grade Calculator!" << std::endl;

	//std::cout << "Please enter the file you wish to open: ";
	//std::cin >> fileName;

	std::ifstream file(ifileName);

	if (!file)
		return (std::cout << "Cannot open file\n"), 1;

	double totalScore(0);

	std::cout << "Reading from file " << ifileName << "...\n";

	for (std::string gradeCategory, scores; std::getline(file, gradeCategory); ) {
		double weight {};

		if (gradeCategory == "Assignments")
			weight = 0.5; //50%
		else if (gradeCategory == "Participation")
			weight = 0.1; //10%
		else if (gradeCategory == "Midterm" || gradeCategory == "Final")
			weight = 0.2; //20%

		if (std::getline(file, scores)) {
			std::istringstream iss(scores);

			double total {};
			size_t count {};

			for (double score {}; iss >> score; iss.ignore(), ++count)
				total += score;

			if (count != 0)
				totalScore += (total / count * weight);
		}
	}

	//std::cout << "Save To (Filename): ";
	//std::cin >> ofileName;

	std::ofstream fileForGrade(ofileName);

	if (!fileForGrade)
		return (std::cout << "Cannot open output file\n"), 2;

	fileForGrade << totalScore << ' ' << calculateLetterGrade(totalScore) << '\n';

	std::cout << "Score & Letter Grade written to file: " << ofileName << '\n';
	std::cout << "Thank you for using my program, have a bless day!\n";
}

char calculateLetterGrade(double score)
{
	char grade {};
	if (score >= 90)
		grade = 'A';
	else if (score >= 80)
		grade = 'B';
	else if (score >= 70)
		grade = 'C';
	else if (score >= 60)
		grade = 'D';
	else
		grade = 'F';

	return grade;
}

Topic archived. No new replies allowed.