How to Read from a file

So I have this project that is due for my class and it involves reading from a file. I dont know how to do that, because every time it asks me for the file name, it says the file wasnt found. Its probably something im missing thats simple but any help is appreciated
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
131
132
133
134
135
136
137
138
139
140
141
142
143
  /*
Alex Smith
4/7/19
leapyear.cpp
assumptions none yet
error checking none yet
input output output sent to screen only
*/

#include<iostream>			// allows i/o
#include<string>			// allows string datatype
#include<fstream>			// allows file i/o

using namespace std;


//declare constants
int JAN = 31;
int FEB = 28;
int MARCH = 31;
int APRIL = 30;
int MAY = 31;
int JUNE = 30;
int JULY = 31;
int AUG = 31;
int SEPT = 30;
int OCT = 31;
int NOV = 30;
int DEC = 31;


// function prototypes
string MonthToString(int numMonth);	// will calculate month name based on month number
bool IsLeap(int yearNum);				// will determine if year is leap year
int CalcDays(int numMonth, int date); // calculates number day of year
void PrintHeading(ofstream& dout, string fileName);
bool ValidMonth(int month);
bool ValidDay(int month, int day, bool leapYear);

int main()
{
	// variables
	int month;			//month from file
	int day;			// day from file
	int year;			// year from file
	string fileName;	// file name to be input by user
	ifstream din;		//input file variable
	ofstream dout;      // output file variable
	string monthName;	// varibale to store the month's name after the function determines it
	int dayOfYear;		// variable to store the day of the year
	bool leapYear;		// variable to store truth value of whether it is a leap year
	bool validDay;
	bool validMonth;

	// prompt user to enter an input file name
	cout << "Please enter the file name that contains the date; press enter." << endl;
	cin >> fileName;
	//associate input file variable with the user input file 
	din.open("days.in");

	//test status of of the input file variable
	if (!din)
	{ // the input file was not found
		//output error message
		cout << "Input file " << fileName << " was not found." << endl;
		cout << "Please re-run program" << endl;
	}
	else
	{ // input file was found

		//initialize LCV
		leapYear = true;
		din >> month >> day >> year; // read in month, day, year

		//while more data in file
		while (din)
		{
			//call SVRF function to determine name of month
			monthName = MonthToString(month);

			// call SVRF to determine if month is valid
			validMonth = ValidMonth(month);

			//call SVRF to determine is day is valid
			validDay = ValidDay(month, day, leapYear);

			//call SVRF function to determine day
			dayOfYear = CalcDays(month, day);

			//call SVRF funtion to determine leap year
			leapYear = IsLeap(year);



			// use if statement to add an extra day if the year is a leap year
			if (leapYear == true && month > 2)
			{
				dayOfYear++;  // adds one day to the day of year if year is a leap year
			}



			if (validDay != true || validMonth != true)
			{
				dout.open("error.txt");
				PrintHeading(dout, fileName);

				if (validDay != true)
				{
					dout << "The date" << month << day << year
						<< " is invalid because the day is invalid." << endl;
				}
				else if (validMonth != true)
				{
					dout << "The date" << month << " " << " " << day << " " << year
						<< " is invalid because the month is invalid." << endl;
				}

			}
			else
			{
				dout.open("results.txt");
				PrintHeading(dout, fileName);

				dout << monthName << " " << day << " is day number " << dayOfYear
					<< " in the year " << year << "." << endl;

			}


			// modify LCV - Get another date
			din >> month >> day >> year;

		}

	}

	din.close();
	dout.close();


	return 0;
}
Here is the rest of the 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
string MonthToString(int numMonth)
{
	/*
	Pre: variable numMonth must be defined
	Post: the month name will be calculated and returned
	Purpose: determine the month based on input number
	*/

	//declare variable[s]
	string monthName;

	// determine month's name based on entered month's digit
	if (numMonth == 1)
	{
		monthName = "January";  //store january as month's name
	}
	else if (numMonth == 2)
	{
		monthName = "February"; // store february as month's name
	}
	else if (numMonth == 3)
	{
		monthName = "March"; // store march as month's name
	}
	else if (numMonth == 4)
	{
		monthName = "April"; //store april as month's name
	}
	else if (numMonth == 5)
	{
		monthName = "May"; //store may as month's name
	}
	else if (numMonth == 6)
	{
		monthName = "June"; //store june as months's name
	}
	else if (numMonth == 7)
	{
		monthName = "July"; //store july as month's name
	}
	else if (numMonth == 8)
	{
		monthName = "August"; //store august as month's name
	}
	else if (numMonth == 9)
	{
		monthName = "September"; //store september as month's name
	}
	else if (numMonth == 10)
	{
		monthName = "October"; // store october as month;s name
	}
	else if (numMonth == 11)
	{
		monthName = "November"; // store november as month's name
	}
	else				// use just "else" because every other option is taken, 
	{					// assuming only valid months are entered
		monthName = "December"; // store december as month's name
	}



	return monthName;	// return the name of the month
}



int CalcDays(int numMonth, int date)
{
	/*
	Pre: variables numMonth and year must be defined
	Post: day number of the year will be calculated and returned
	Purpose: calculate day number in the year
	*/

	//declare vriable[s]
	int dayOfYear;

	//determine the day based on the day and month
	if (numMonth == 1)
	{
		dayOfYear = date;  
		//for january, the day of the year is just the date entered
	}
	else if (numMonth == 2)
	{
		dayOfYear = date + JAN; 
		//february, the day is equal to the date plus the days from january
	}
	else if (numMonth == 3)
	{
		dayOfYear = date + JAN + FEB; 
		// march, the day is equal to the date plus the days
	}	// from jan and feb
	else if (numMonth == 4)
	{
		dayOfYear = date + JAN + FEB + MARCH; 
		//april, day is equal to the date plus the days
	}	// from jan, feb, march
	else if (numMonth == 5)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL; 
		//may, day is equal to the date plus the
	}   // days from jan, feb, march...
	else if (numMonth == 6)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY; 
		//june, day is equal to the date plus
	}	// plus the days from all preceeding months
	else if (numMonth == 7)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE;
		// july, day is equal to the date 
	}	//  plus the days from all preceeding months
	else if (numMonth == 8)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE; 
		// august, day is equal to thE 
	}	// date plusthe days from all preceeding months
	else if (numMonth == 9)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE + JULY + AUG; 
		// september, day is equal to
	}	//the date plus all preceeding months
	else if (numMonth == 10)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE + JULY + AUG + SEPT;	
		//october, the day is equal
	}	// to the date plus all preceeding months
	else if (numMonth == 11)
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE + JULY + AUG 
			+ SEPT + OCT; 
		// november
	}	// the date is equal to the date plus all preceeding months		
	else
	{
		dayOfYear = date + JAN + FEB + MARCH + APRIL + MAY + JUNE + JULY + AUG
			+ SEPT + OCT + NOV;
		//december
	}  //the date is equal to the date plus all preceeding months



	return dayOfYear;	//returns the day of the year to main
}



bool IsLeap(int yearNum)
{
	/*
	Pre: variable yearNum must be defined
	Post: the truth of whether it is a leap year will be determined and returned
	Purpose: calculate if year is a leap year
	*/

	//declare variable[s]
	bool leapYear;

	// if the year is divisble by 4, 100, or 400
	if (yearNum % 4 == 0 || yearNum % 100 == 0 && yearNum % 400 == 0)
	{   // it is true it is a leap year
		leapYear = true;
	}
	else
	{// if it is not, it is false it is a leap year
		leapYear = false;
	}


	return leapYear;	//return true or false
}


void PrintHeading(ofstream& dout, string fileName)
{

	dout << "*********************************" << endl;
	dout << "*                               *" << endl;
	dout << "*   Days Calculation Program    *" << endl;
	dout << "*     File name: " << fileName << "      *" << endl;
	dout << "*                               *" << endl;
	dout << "*********************************" << endl;


}


bool ValidMonth(int month)
{
	bool validMonth;    // variable to store is month is valid

	if (month > 12 || month < 1)
	{
		validMonth = false;
	}
	else
	{
		validMonth = true;
	}


	return validMonth;
}


bool ValidDay(int month,int day, bool leapYear)
{
	bool validDay;

	if (month == 9, 4, 6, 11 && day > 30)
	{
		validDay = false;
	}
	else if (month == 2 && day > 28 && leapYear == false)
	{
		validDay = false;
	}
	else if (month == 1, 3, 5, 7, 8, 10, 12 && day > 31)
	{
		validDay = false;
	}
	else
	{
		validDay = true;
	}

	return validDay;
}
You seem to ask for the filename but then try to open something entirely different:

(lines 57-59)

1
2
3
	cin >> fileName;
	//associate input file variable with the user input file 
	din.open("days.in");

Surely you want to be attempting to open fileName rather than "days.in".

Also, FYI, lines 17-29, your comment indicates the variables are constants, but they're not constants, just regular integer variables. You need to use the const keyword if you actually want them to be constants:

For example:

1
2
3
4
5
//declare constants
const int JAN = 31;
const int FEB = 28;
const int MARCH = 31;
// etc 

http://www.cplusplus.com/doc/tutorial/constants/

(note, I think you'll tend to find that the usual convention for naming constants is that they're named in lowercase, rather than capitals).

Additionally, if you wanted to, you could also shorten your code a little by using switch statements in a couple of places, rather than all of the else-if's that you have. For example:

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
string MonthToString(int numMonth)
{
	/*
	Pre: variable numMonth must be defined
	Post: the month name will be calculated and returned
	Purpose: determine the month based on input number
	*/

	//declare variable[s]
	string monthName;

	// determine month's name based on entered month's digit
	switch (numMonth) {
	    case 1:  monthName = "January";    //store January as month's name
	             break;
	    case 2:  monthName = "February";  //store February as month's name
	             break;
	    case 3:  monthName = "March";  //store March as month's name
	             break;
	    case 4:  monthName = "April";  //store April as month's name
	             break;
	    case 5:  monthName = "May";  //store May as month's name
	             break;
	    case 6:  monthName = "June";  //store June as month's name
	             break;
	    case 7:  monthName = "July";  //store July as month's name
	             break;
	    case 8:  monthName = "August";  //store August as month's name
	             break;
	    case 9:  monthName = "September";  //store September as month's name
	             break;
	    case 10: monthName = "October";  //store October as month's name
	             break;
	    case 11: monthName = "November";  //store November as month's name
	             break;
	    case 12: monthName = "December";  //store December as month's name
	             break;
            default: monthName ="???";
	}

return monthName;	// return the name of the month
}

There's some information about switch statements at the bottom of the page here:

http://www.cplusplus.com/doc/tutorial/control/

I tend to find that it's easier to read switch statements rather than a whole lot of else-if statements, and also makes the code easier to maintain. (but maybe you're not able to use them if you've not covered them in class yet).

Not that it's necessary, but you could also shorten your ValidMonth function quite a bit if you wanted, while keeping it readable. For example:

1
2
3
4
5
6
bool ValidMonth(int month)
{
    if (month > 12 || month < 1) return false;

return true;
}


Also, while it will compile, I don't think your statements on lines 213 and 221 will give the results you expect; I think you'll find supplying a comma-separated list of values is not the way to do things. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

void test(int z){
 if (z==6,7,8)  // this is wrong; it will still print "hello", even when argument is 5
 {
   std::cout << "hello\n";
 }
}

int main(){
  test(5);
return 0;
}

I didn't look at any of your other code really, so maybe there are other things too, but I'm sure you'll find them as you test your program. You do have great commenting throughout your code; that's a really good habit.

Hope that helps.
Last edited on
Hello lazorgod,

Overall the program works. I do have some suggestions and explanations that should help.

You may not be use to it yer or even covered its use, but I follow "iostream" with the header "iomanip". As the name suggests they are manipulators to the output streams. You can read up on it at:
http://www.cplusplus.com/reference/iomanip/ and http://www.cplusplus.com/reference/ios/ios_base/fmtflags/ I will show you its use later.

For the line using namespace std; // <--- Best not to use. The comment says it best.

Lines 18 - 29 as Cheddar99 has said you need to make these variables constants. In contrast to his note everything I have read here and elsewhere says the a variable defined as a constant should be in capital letters. Whether you put two or more together as one word or use the underscore, as a space, to separate words is your choice, but choose one method and be consistent.

If your compiler is up to the C++11 standards the newer form for numeric variables is constexpr otherwise const will do. From C++11 on the {}s or uniform initializer is easiest to use. An empty set {} will initialize to the correct form of zero based on the type of variable. Or you could put a number inside the {}. This also works with std::strings.

Example:
1
2
3
constexpr int JAN{ 31 };
constexpr int FEB{ 28 };
constexpr int MARCH{ 31 };

Something that would make the coding easier is:
1
2
const std::string MONTHS[]{ "", "January", "February", "March" };
constexpr int MONTH_LENGTHS[]{ 0, 31, 28, 31 };



Note: the first element of each array is empty, or call it more a place holder, to allow January to be in element "1" of the array. This way when you use "numMonth", This works, but ("monthNum") is a better description of what it is used for and easier to read, can be used as the subscript to access the correct month. This is a case of making the array one larger and not using element zero.

By using the array "MONTHS" you could eliminate the need for the function "MonthToString" and just say
outFile << MONTHS[month] << " " << day << ... in "main". Or if you need the function you could shorten it to just:
1
2
3
4
std::string MonthToString(int numMonth)
{
	return MONTHS[numMonth];
}


Much easier than all those is/else if statements or even a switch.

Inside "main" I like to initialize all the variables to be save in the knowledge that they have a known value before they are used. In your program this is not necessary as these variables are given a value before they are used.

For your file streams. Sometimes it is easier to give each file stream its own variable name like:
1
2
3
std::ifstream inFile("Days.txt");
std::ofstream outFileErr("error.txt");
std::ofstream outFileRes("results.txt");


In this example you not only create the file stream and variable name "inFile" what is in the ()s will open the file at the time the stream is created. What is in the ()s can either be the file name in double quotes or a variable name like your "fileName".

Your if statement if (!inFile) is good, but I would add one last line:
return 1; // exit(1); // if not in "main". Since zero denotes a normal return from the program any number greater than zero means there is a problem. Should you have more than one if statement like this using different numbers for the return statements can help to track down what went wrong. The reason for the return statement is that there is no point in continuing with the program until you fix the problem.

In contrast opening a file stream for output is less likely to have a problem because if the file name does not exist it will create it, but there is still a possibility that something could go wrong and it is a good idea to check the output file streams after they are opened.

In your original code you have:
1
2
3
4
5
6
if (!din)
{
}
else
{
}


This may work, but, and I am sorry I can not think of a nice way to say this, putting what is in "main" inside an if block or else block is not the best way to write the code. And it is kind of tacky. The point of the return statement in the if block is to exit the program and fix the problem. Should you bypass the if statement then you just continue on with the program.

What I can say is that an if statement does not always need an else statement or even an else if statement. The if statement can work on its own do what it has to do and then continue with the program.

After running the program a couple of times I realized that the "PrintHeading" function should be called before the while loop and not inside the loop where it was printing to many headings.

In your while condition while (din) and it is much better than while (!din.eof()) which does not work the way you think it does. By the time the while condition figures you have reached eof you will have processed your last read a second time.

To read a file of unknown length this is most often used: while (inFile >> month >> day >> year). This way when it tries to read past end of file or either of the other two variables has a problem the file stream will set the eof, fail or bad bit making the condition false and the while loop will end.

Inside the while loop you have problems with your file stream. Opening the file stream "dout" inside the while loop works the first time through the loop, but causes the stream to fail when you try to open "dout" when it is already open. After that you are nor able to write to the file any more. The next problem is when you try to open "dout" for "errost.txt". Since "dout" is already open for "results.txt" it will cause the stream "dout" to fail and nothing will be written to either file.

One solution is to open the stream for append and after writing to it close the stream so it can be used again. This also applies when you open the stream for "errors.txt". The problem is that this will cereate overhead that could slow the program down.

I would say the better choice is to open three file streams before the while loop and then close them after the while loop. This way you use the output files as you need them and close them when you are finished reading the input file.

Using the array I showed you the "CalcDays" function can be reduced to a for loop:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int CalcDays(int numMonth, int date)
{
	int dayOfYear{};

	if (numMonth == 1)
	{
		return date;  //for January, the day of the year is just the date entered
	}

	for (int lc = 1; lc < numMonth; lc++)
	{
		dayOfYear += MONTH_LENGTHS[lc];
	}

	return (dayOfYear + date);
}


End part 1.
Part 2.

In the function "IsLeep" if you define the variable as bool leapYear{ false }; You will not need the else statement as the variable is already set to "false" and if you do not enter the if block it is set to return "false". You could also with this function without the variable be just putting return true;in the if block and return false; otherwise.

And if you really want to get short the function could just say
return (yearNum % 4 == 0 || yearNum % 100 == 0 && yearNum % 400 == 0); which would return a zero for false or something greater than zero for true.

In the "PrintHeadings" function I made one change:
dout << "* File name: " << std::left << std::setw(15) << fileName << "*" << std::endl; I had to put the "left" in because on my IDE it was setting the string to the right and it did not look right. The "setw" must preceed the variable or whatever follows to affect it. What this does is set a block of 15 places for the file name and puts the "*" in the proper place. If you can not use this yet then you will have to adjust the string of spaces to get the "*" in the proper column. The problem is that you will have to do this every time the length of the file name changes.

Cheddar99 example for "ValidMonth" is as good as anything I could come up with.

I have not looked closely at the function "ValidDay" yet because it is short enough I just left it as is for now.

As a note and something I noticed: if (leapYear == true. This is a waste of time because the variable is defined as a "bool" so it can only be "0" "false" or "1", (or any number greater than zero), "true". So the if statement just need to be if (leapYear && month > 2) and it will work just fine. You could also do:
if ((yearNum % 4 == 0 || yearNum % 100 == 0 && yearNum % 400 == 0) && month > 2) and eliminate the need for the function.

Hope that helps,

Andy
Hey Andy; yeah, you're obviously correct about the naming convention for constants. To be honest, being something of a C++ newbie myself, I wasn't certain on the convention, and so I searched and found some site which suggested it was lowercase.

However, having read your post and searched some more, even though there are a good few examples of using lowercase constant names, it seems that the much more generally accepted standard is to use uppercase names, so I've updated my post accordingly. I should have been more thorough originally.

Cheddar.
Last edited on
@Cheddar99,

I did the same thing once by not researching far enough. No worries, it happens.

I also found that naming constants with all caps it helps to remind you that it is a constant that can not be changed.

Andy
Topic archived. No new replies allowed.