Write to the end of .csv file

Pages: 12
I have a .csv file like this

1
2
3
4
5
6
7
8
9
10
11
No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
2,18127222,Tran Van,A,Female,9/6/2000
3,18127223,Le Nguyen,Ngoc,Female,8/1/2000
4,18127224,Donald,Trump,Male,12/5/2000
5,18127225,Mike,Pence,Male,21/4/2000
6,18127226,Nguyen Xuan,Phuc,Male,2/9/2000
7,18127227,Nguyen Phu ,Trong,Male,12/12/2000
8,18127228,Pham Binh,Minh,Male,13/3/2000
9,18127229,Vu Duc,Dam,Male,3/2/2000
10,18127230,To ,Lam,Male,4/6/2000

So far I've tried to write to the end of that file (using the same file as input).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
string newLastName, newFirstName, newID, newGender, newDob;
	cout << "Enter new ID: ";
	cin >> newID;
	cout << "Enter new first nme: ";
	cin >> newFirstName;
	cout << "Enter new last name: ";
	cin >> newLastName;
	cout << "Enter new gender: ";
	cin >> newGender;
	cout << "Enter dob: ";
	cin >> newDob;
	out.open("E:/timetable.csv", std::ios::app);
	out << stoi(student[sizeof(student)].no) + 1 << "," << newID << "," << newFirstName << "," << newLastName << "," << newGender << "," << newDob << endl;
	out.close();

But when I run it then open the .csv file, there's nothing change, it still the same as it was.
What did I go wrong?
You should check that the file is actually opened correctly, and inform the user if it failed.



Hello thinhphucvang,

Try this after your open statement:
1
2
3
4
5
6
if (!outFile)
{
	std::cout << "\n File \"" << "timetable.csv" << "\" did not open" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread".
	return 1;  //exit(1);  // If not in "main".
}
Line 4 is optional as is the header files that it needs.

And what is this and where did it come from? stoi(student[sizeof(student)].no) + 1

It would help if you post the whole code so that it can be compiled and tested. There may be other problems that you may not have found yet.

Hope that helps,

Andy
Hello thinhphucvang,

When i was testing your program I realized a potential problem. When using cin >> newLastName; and then trying to enter a name like "Nguyen Van" only "Nguyen" will be extracted from the input buffer and you will loose the second part. Using std::getline(std::cin, newLastName); will get everything typed in.

Your input code would work better as:
1
2
3
4
5
6
7
8
9
10
11
12
	std::cout << "Enter new ID: ";
	std::cin >> newID;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "Enter new first nme: ";
	std::getline(std::cin, newFirstName);
	std::cout << "Enter new last name: ";
	std::getline(std::cin, newLastName);
	std::cout << "Enter new gender: ";
	std::cin >> newGender;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "Enter dob: ";
	std::getline(std::cin, newDob);

Lines 3 an 10 are needed to clear the input buffer before the use of "std::getline".

I set up the output file stream differently because I can not use "E:/" and it worked for my setup.

I changed this part of the code: stoi(student[sizeof(student)].no) + 1 to just a variable (studentNo + 1) to make it work for now.

Hope that helps,

Andy

P.S. The file now looks like:

No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
2,18127222,Tran Van,A,Female,9/6/2000
3,18127223,Le Nguyen,Ngoc,Female,8/1/2000
4,18127224,Donald,Trump,Male,12/5/2000
5,18127225,Mike,Pence,Male,21/4/2000
6,18127226,Nguyen Xuan,Phuc,Male,2/9/2000
7,18127227,Nguyen Phu ,Trong,Male,12/12/2000
8,18127228,Pham Binh,Minh,Male,13/3/2000
9,18127229,Vu Duc,Dam,Male,3/2/2000
10,18127230,To ,Lam,Male,4/6/2000
11,18127232,Jane,Doe,F,04/02/1959
12,18127234,Bob,Vander Horne,M,10/12/1945
13,18127250,Nigel,Smithe,M,11/20/1960

Last edited on
Here's the full code, it's not very tidy.
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
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
using namespace std;
struct Student
{
	string no, id, last_name, first_name, gender, dob;
};
struct Timetable
{
	string courses_no, courses_id, lecture_account, class_name, lectures_account, start, end, day, start_hour, end_hour, room;
};
int main()
{
	ifstream in;
	in.open("E:/students.csv");
	Student *student;
	student = new Student[100];
	string  No, student_id, Last_name, First_name, Gender, DoB;
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No, ',');
		getline(in, student_id, ',');
		getline(in, Last_name, ',');
		getline(in, First_name, ',');
		getline(in, Gender, ',');
		getline(in, DoB, '\n');
		for (int i = 0; i < 100; i++)
		{
			getline(in, student[i].no, ',');
			getline(in, student[i].id, ',');
			getline(in, student[i].last_name, ',');
			getline(in, student[i].first_name, ',');
			getline(in, student[i].gender, ',');
			getline(in, student[i].dob, '\n');
		}
		in.close();
	}
	ofstream out;
	out.open("E:/student.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No << " " << student_id << " " << Last_name << " " << First_name << " " << Gender << " " << DoB << endl;
		for (int i = 0; i < 100; i++)
		{
			out << student[i].no << " " << student[i].id << " " << student[i].last_name << " " << student[i].first_name << " " << student[i].gender << " " << student[i].dob << endl;
		}
		out.close();
	}

	Timetable *t;
	t = new Timetable[100];
	string No_t, Course_ID, LectureAccount, Class, LecturesAccount, Start_Date, End_Date, Day_of_week, Start_hour, End_hour, Room;
	in.open("E:/timetable.csv");
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No_t, ',');
		getline(in, Course_ID, ',');
		getline(in, LectureAccount, ',');
		getline(in, Start_Date, ',');
		getline(in, End_Date, ',');
		getline(in, Day_of_week, ',');
		getline(in, Start_hour, ',');
		getline(in, End_hour, ',');
		getline(in, Room, '\n');
		for (int i = 0; i < 100; i++)
		{
			getline(in, t[i].courses_no, ',');
			getline(in, t[i].courses_id, ',');
			getline(in, t[i].lecture_account, ',');
			getline(in, t[i].start, ',');
			getline(in, t[i].end, ',');
			getline(in, t[i].day, ',');
			getline(in, t[i].start_hour, ',');
			getline(in, t[i].end_hour, ',');
			getline(in, t[i].room, '\n');
		}
		in.close();
	}
	out.open("E:/timetable.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No_t << " " << Course_ID << " " << LectureAccount << " " << Start_Date << " " << End_Date << " " << Day_of_week << " " << Start_hour << " " << End_hour << " " << Room << endl;
		for (int i = 0; i < 100; i++)
		{

			out << t[i].courses_no << " " << t[i].courses_id << " " << t[i].lecture_account << " " << t[i].start << " " << t[i].end << " " << t[i].day << " " << t[i].start_hour << " " << t[i].end_hour << " " << t[i].room << endl;
		}
		out.close();
	}
	string newLastName, newFirstName, newID, newGender, newDob;
	cout << "Enter new ID: ";
	cin >> newID;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter new first name: ";
	getline(cin, newFirstName);
	cout << "Enter new last name: ";
	getline(cin, newLastName);
	cout << "Enter new gender: ";
	cin >> newGender;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter dob: ";
	getline(cin, newDob);

	out.open("E:/students.csv", std::ios::app);
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		int newNo = stoi(student[sizeof(student)].no) + 1;
		out << newNo << "," << newID << "," << newFirstName << "," << newLastName << "," << newGender << "," << newDob << endl;
		out.close();
	}
	system("pause");
}

I meant to create a new No number, following 10 is 11, looks like the code stoi(student[sizeof(student)].no) + 1 is not what expected, it printed out number 6.
1
2
3
4
5
6
7
8
9
10
11
12
No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
2,18127222,Tran Van,A,Female,9/6/2000
3,18127223,Le Nguyen,Ngoc,Female,8/1/2000
4,18127224,Donald,Trump,Male,12/5/2000
5,18127225,Mike,Pence,Male,21/4/2000
6,18127226,Nguyen Xuan,Phuc,Male,2/9/2000
7,18127227,Nguyen Phu ,Trong,Male,12/12/2000
8,18127228,Pham Binh,Minh,Male,13/3/2000
9,18127229,Vu Duc,Dam,Male,3/2/2000
10,18127230,To ,Lam,Male,4/6/2000
6,18127225,An,Vu,Male,9/8/2001
Oh I see the problem: sizeof(student) size is 5 since its contain 6 string elements like
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
Now the problem is seen, leading to the solution: I need to convert the last No number (number 10) into an integer and print it out. How to get that number?
You really should consider several functions and reusing your output stream for multiple streams may cause problems if one of the streams happen to fail.

Also if any of the files fail to open you probably should "abort" the program.

1
2
Timetable *t;
	t = new Timetable[100];

There is no need for this manual memory management since you're using a constant when creating the array. Plus you really should prefer a std::vector instead of the array.

How to get that number?

Well you seem to be reading a file that contains this number maybe you should keep track of it to find the largest value. Another option might be to keep a count of the number of students in your input file.



Last edited on
Hello thinhphucvang,

You should find that this works better than what you have started with. Based in part on jlb's suggestions. I added some extras that you may not want to use.

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
#include <iostream>
#include <iomanip>  // <--- for setw() and setprecision.
#include <fstream>
#include <limits>
#include <string>
#include <chrono>
#include <thread>

using namespace std;  // <--- Best not to use.

struct Student
{
	string no, id, last_name, first_name, gender, dob;
};

struct Timetable
{
	string courses_no, courses_id, lecture_account, class_name, lectures_account, start, end, day, start_hour, end_hour, room;
};

int main()
{
	constexpr size_t MAXSIZE{ 100 };

	ifstream in;
	size_t index{}, tIndex{};
	Student student[MAXSIZE];
	string  No, student_id, Last_name, First_name, Gender, DoB;

	in.open("students.csv");
	
	if (!in)
	{
		cout << "Error!\n";
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread".
		return 1;
	}

	// <--- To Read the headings.
	getline(in, No, ',');
	getline(in, student_id, ',');
	getline(in, Last_name, ',');
	getline(in, First_name, ',');
	getline(in, Gender, ',');
	getline(in, DoB, '\n');

	// <--- To read the rest of the file.
	//for (int i = 0; i < 100; i++)
	while(getline(in, student[index].no, ','))
	{
		getline(in, student[index].id, ',');
		getline(in, student[index].last_name, ',');
		getline(in, student[index].first_name, ',');
		getline(in, student[index].gender, ',');
		getline(in, student[index++].dob, '\n');
	}

	in.close();

	ofstream out;
	out.open("student.txt");

	if (!out)
	{
		cout << "Error!\n";
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread".
		return 2;
	}

	out << No << "  " << student_id << "   " << Last_name << "     " << First_name << "  " << Gender << "    " << DoB << endl;

	for (int i = 0; i < index; i++)
	{
		out << right << setw(2) << student[i].no << "   "
		<< left << setw(10) << student[i].id << "  "
		<< setw(12) << student[i].last_name << "  "
		<< setw(11) << student[i].first_name << " "
		<< setw(6) << student[i].gender << "  "
		<< student[i].dob << endl;

	}

	out.close();

	return 0;
}

This only covers the first part. When I got to the line in.open("timetable.csv"); I had to stop because I do not have this file to use.

The variable "index" is defined outside the while loop and keeps track of the number of records that are read.

The while loop is a better way to read a file of unknown length without causing extra problems.

line 55 adds one to "index" when it is finished using it.

Your line of code : int newNo = stoi(student[sizeof(student)].no) + 1;
should be: int newNo = stoi(student[index - 1].no) + 1;

By using "sizeof(student)" you are getting a different number than you need. What you need is the "no" from the last element in the array.

Since the file "timetable.csv" is different from "student.csv" I will need something to work with to check the rest of the program.

The last thing I realized is that at the end of the program you enter new information and write it to the "student.csv" file, but what about the "student" array. Would you not want to add this information to the array and what about "timetable.???"?

Hope that helps,

Andy

Edit:
Last edited on
Hello thinhphucvang,

Looking back at the program I can not use "E:/students.csv" as my "E" drive is not usable for storing files that can change in size. So I came up with this:
1
2
3
4
const string inFileName{ "students.csv" };
//const string inFileName{ "E:/students.csv" };

in.open(inFileName);

By changing the comments you can use the version that works, with the least amount of typing. This same concept can work for the other files. You will just need to change the variable names as you add more.

Hope that helps,

Andy
Last edited on
I got a sleep for the night, but I did not feel so good
Anyway the timetable.csv is:
1
2
3
4
5
6
7
8
9
No,Course ID,LectureAccount,Class,LecturesAccount,Start Date,End Date,Day of week,Start hour:Minute,End hour:Minute,Room
1,CTT008,Ky thuat lap trinh,18CLC2,nmhuy,2019-01-07,2019-04-13,tues,13:30,15:10,B.40
2,CTT008-TH,Ky thuat lap trinh thuc hanh,18CLC2,htthanh,2019-01-07,2019-04-13,thur,7:30,9:30,I.61
3,CTT010,Nhap mon cong nghe thong tin 2,18CLC2,vhviet,2019-01-07,2019-04-13,wed,7:30,11:10,I.23
4,CTT010-TH,Nhap mon cong nghe thong tin 2 thuc hanh,18CLC2,pmhoang,2019-01-07,2019-04-13,mon,15:30,17:30,C.23A
5,CTH026,Giai tich B1,18CLC2,nttvan,2019-01-07,2019-04-13,sat,7:30,11:10,I.42
6,CTT026-TH,Giai tich B1-TH,18CLC2,nthnhung,2019-01-07,2019-04-13,wed,13:30,15:30,I.71
7,KTH001,Kinh te dai cuong,18CLC2,pxkien,2019-01-07,2019-04-13,fri,7:30,11:10,I.41
8,CTH001,Nhung nguyen li co ban cua CN mac le nin,18CLC2,nqhuy,2019-01-07,2019-04-13,mon,7:30,11:10,B.11A

Until now I realized through your words that I hadn't put those new information into the array. Is it legal if I do like this?
1
2
student[index + 1].id = newId;
student[index + 1].last_name = newFirstName;

Here what I've fix:
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
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
#include <iomanip>
using namespace std;
struct Student
{
	string no, id, last_name, first_name, gender, dob;
};
struct Timetable
{
	string courses_no, courses_id, lecture_account, class_name, lectures_account, start, end, day, start_hour, end_hour, room;
};
int main()
{
	size_t index{}, tIndex{};
	ifstream in;
	in.open("E:/students.csv");
	Student student[100];
	string  No, student_id, Last_name, First_name, Gender, DoB;
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No, ',');
		getline(in, student_id, ',');
		getline(in, Last_name, ',');
		getline(in, First_name, ',');
		getline(in, Gender, ',');
		getline(in, DoB, '\n');
		while (getline(in, student[index].no, ','))
		{
			getline(in, student[index].id, ',');
			getline(in, student[index].last_name, ',');
			getline(in, student[index].first_name, ',');
			getline(in, student[index].gender, ',');
			getline(in, student[index++].dob, '\n');
		}
		in.close();
	}
	ofstream out;
	out.open("E:/student.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No << "  " << student_id << "   " << Last_name << "     " << First_name << "  " << Gender << "    " << DoB << endl;
		for (int i = 0; i < index; i++)
		{
			out << right << setw(2) << student[i].no << "   ";
			out << left << setw(10) << student[i].id << "  ";
			out << setw(12) << student[i].last_name << "  ";
			out << setw(11) << student[i].first_name << " ";
			out << setw(6) << student[i].gender << "  ";
			out	<< student[i].dob << endl;
		}
		out.close();
	}

	Timetable t[100];
	string No_t, Course_ID, LectureAccount, Class, LecturesAccount, Start_Date, End_Date, Day_of_week, Start_hour, End_hour, Room;
	in.open("E:/timetable.csv");
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No_t, ',');
		getline(in, Course_ID, ',');
		getline(in, LectureAccount, ',');
		getline(in, Start_Date, ',');
		getline(in, End_Date, ',');
		getline(in, Day_of_week, ',');
		getline(in, Start_hour, ',');
		getline(in, End_hour, ',');
		getline(in, Room, '\n');
		while (getline(in, t[tIndex].courses_no, ','))
		{
			getline(in, t[tIndex].courses_no, ',');
			getline(in, t[tIndex].courses_id, ',');
			getline(in, t[tIndex].lecture_account, ',');
			getline(in, t[tIndex].start, ',');
			getline(in, t[tIndex].end, ',');
			getline(in, t[tIndex].day, ',');
			getline(in, t[tIndex].start_hour, ',');
			getline(in, t[tIndex].end_hour, ',');
			getline(in, t[tIndex++].room, '\n');
		}
		in.close();
	}
	out.open("E:/timetable.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No_t << " " << Course_ID << " " << LectureAccount << " " << Start_Date << " " << End_Date << " " << Day_of_week << " " << Start_hour << " " << End_hour << " " << Room << endl;
		for (int i = 0; i < tIndex; i++)
		{
			out << t[i].courses_no << " " << t[i].courses_id << " " << t[i].lecture_account << " " << t[i].start << " " << t[i].end << " " << t[i].day << " " << t[i].start_hour << " " << t[i].end_hour << " " << t[i].room << endl;
		}
		out.close();
	}
	string newLastName, newFirstName, newID, newGender, newDob;
	cout << "Enter new ID: ";
	cin >> newID;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter new first name: ";
	getline(cin, newFirstName);
	cout << "Enter new last name: ";
	getline(cin, newLastName);
	cout << "Enter new gender: ";
	cin >> newGender;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter dob: ";
	getline(cin, newDob);
	
	student[index + 1].no = index + 1;
	student[index + 1].id = newID;
	student[index + 1].first_name = newFirstName;
	student[index + 1].last_name = newLastName;
	student[index + 1].gender = newGender;
	student[index + 1].dob = newDob;
	out.open("E:/students.csv", std::ios::app);
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << student[index + 1].no << "," << student[index + 1].id << "," << student[index + 1].first_name << "," << student[index + 1].last_name << "," << student[index + 1].gender << "," << student[index + 1].dob << endl;
		out.close();
	}
	system("pause");
}

The file is now:
1
2
3
4
5
6
7
8
9
10
11
12
13
No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
2,18127222,Tran Van,A,Female,9/6/2000
3,18127223,Le Nguyen,Ngoc,Female,8/1/2000
4,18127224,Donald,Trump,Male,12/5/2000
5,18127225,Mike,Pence,Male,21/4/2000
6,18127226,Nguyen Xuan,Phuc,Male,2/9/2000
7,18127227,Nguyen Phu ,Trong,Male,12/12/2000
8,18127228,Pham Binh,Minh,Male,13/3/2000
9,18127229,Vu Duc,Dam,Male,3/2/2000
10,18127230,To ,Lam,Male,4/6/2000

,12121212121212,Nguyen Xuan,Phuc,Male,9/8/1999

The last line's No is an arrow icon, I can't paste it into here?
Where do the blank line and the arrow come from?
I changed the output:
1
2
3
4
int newNo = stoi(student[index - 1].no) + 1;
		out << newNo << "," << student[index + 1].id << "," << student[index + 1].first_name << "," << student[index + 1].last_name << "," << student[index + 1].gender << "," << student[index + 1].dob << endl;
		out.close();
	}

Now the compiler told me:
1
2
Exception thrown at 0x758B18A2 in ktlt.exe: Microsoft C++ exception: std::invalid_argument at memory location 0x008F34A0.
Unhandled exception at 0x758B18A2 in ktlt.exe: Microsoft C++ exception: std::invalid_argument at memory location 0x008F34A0.

What does this error is?
Hello thinhphucvang,

Like you its bed time. I will check it out in the morning.

Andy
While you're in bed, now my place is 12:25 PM and I have fixed 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
	string newLastName, newFirstName, newID, newGender, newDob;
	cout << "Enter new ID: ";
	cin >> newID;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter new first name: ";
	getline(cin, newFirstName);
	cout << "Enter new last name: ";
	getline(cin, newLastName);
	cout << "Enter new gender: ";
	cin >> newGender;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter dob: ";
	getline(cin, newDob);
	
	student[index + 1].id = newID;
	student[index + 1].first_name = newFirstName;
	student[index + 1].last_name = newLastName;
	student[index + 1].gender = newGender;
	student[index + 1].dob = newDob;
	out.open("E:/students.csv", std::ios::app);
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << index + 1 << "," << student[index + 1].id << "," << student[index + 1].first_name << "," << student[index + 1].last_name << "," << student[index + 1].gender << "," << student[index + 1].dob << endl;
		out.close();
	}
	system("pause");

And the output is:
1
2
3
4
5
6
7
8
9
10
11
12
13
No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,4/11/2000
2,18127222,Tran Van,A,Female,9/6/2000
3,18127223,Le Nguyen,Ngoc,Female,8/1/2000
4,18127224,Donald,Trump,Male,12/5/2000
5,18127225,Mike,Pence,Male,21/4/2000
6,18127226,Nguyen Xuan,Phuc,Male,2/9/2000
7,18127227,Nguyen Phu ,Trong,Male,12/12/2000
8,18127228,Pham Binh,Minh,Male,13/3/2000
9,18127229,Vu Duc,Dam,Male,3/2/2000
10,18127230,To ,Lam,Male,4/6/2000
11,1414141,John Holly,Mclane,Male,9/9/1999
12,11111111,John,Lovely,Female,9/9/1999

Anyway, get a good sleep!
Hello thinhphucvang,

In your latest code I see things that age good and some things that still need fixed.

At the beginning of main I have this:
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
int main()
{
	constexpr size_t MAXSIZE{ 100 };

	size_t index{}, tIndex{};

	// <--- File names.
	const string inFileName{ "students.csv" };
	//const string inFileName{ "E:/students.csv" };
	const string inFileName2{ "timetable.csv" };
	//const string inFileName2{ "E:/students.csv" };
	const string outFileName3{ "students.txt" };
	//const string outFileName3{ "E:/students.csv" };
	const string outFileName4{ "timetable.txt" };
	//const string outFileName4{ "E:/timetable.csv" };

	Student student[MAXSIZE];
	string  No, student_id, Last_name, First_name, Gender, DoB;  // <--- For headings.

	ifstream in;
	in.open(inFileName);

	if (!in)
	{
		cout << "\n  Error! file \"" << inFileName << "\" did not open." << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread". Optional.
		return 1;  //exit(1);  // If not in "main".
	}


The first line constexpr size_t MAXSIZE{ 100 }; or can be written as const size_t MAXSIZE{ 100 }; May not seem to be of much use now, but is very helpful in the future.

With a line like: Student student[MAXSIZE]; and Timetable t[MAXSIZE]; the use of "MAXSIZE" may not seem necessary, but when you have several of these and you define some of these within the program and also if used in for loops through out the program its use becomes clearer.

By defining "MAXSIZE" and other variables like at the beginning of the program you only have one place to make a change and do not have to hunt through the program to fine everything that needs changes and possibly missing something. By putting them at the top of "main" or after the "#includes" they are easy to find when a change is needed.

In the future when you start adding other function to the main file you will find putting these constant variables in the global file scope will allow you to use them anywhere in the file.

When writing variable names the generally accepted way is to start a regular variable with a lower case letter. After thet the "camelCase", (starting the second and any other parts with a capital letter), method seems to be the most often used followed by using the underscore as in: last_name.

Starting a name with a capital letter is used for "classe"s and "struct"s.

Function names, that you write, tend to start with lower case letters.

This may be my preference but I moved:
1
2
ifstream in;
in.open(inFileName);

After the definition of the variables because I like to keep some together. This can even be shortened to just ifstream in(inFileName);. This will create the file stream and open the file at the same time. A small time saver.

In the if condition all you need is "!in". There is no need for any fancy function to check if the file is open. Inside the if statement, and as jlb pointed out, if you end up here you need to exit the program and fix the problem. If you allow the program to continue with a file stream that will not work you are just wasting your time and wondering why you have no information from the file to work with.

You should notice that by defining const string inFileName{ "students.csv" }; you can use it to open the file stream and also in the if statement in the "cout" statement to show what file did not open.

The line: return 1; //exit(1); // If not in "main". . If you use this in the "main" file the return is the best choice. If this is in a function the "return 1" could be a problem returning you back to where the function was called form. If the function does not return an "int" this is also a problem. A "return 0" means that everything worked and there are no problems. Any value greater than zero means that there is a problem. By using numbers greater than zero this can help you figure out where a problem is. Your program is a good example of using this.

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

The "else" block is not necessary. Should you enter the if bloce you should exit the program to fix the problem. Otherwise you will by pass the if statement and just continue with the program. An "if" statement does not always need an "else" statement. It does not make any difference if you have one, but in this case it is not necessary.

The next part that reads the "student.csv" file is OK and is the part that writes to the "student.txt" file.

I see you kept the "setw"s I added. I think that doing this makes the "student.txt" file nicer to read when things line up.

I have not tested this yet, but I do see a problem to start with:
1
2
3
4
while (getline(in, t[tIndex].courses_no, ','))
{
	//getline(in, t[tIndex].courses_no, ',');
	getline(in, t[tIndex].courses_id, ',');

The while condition is reading "t[tIndex].courses_no". The reason for doing this is that when the while condition tries to read past the end of the file the file stream will fail and the while condition will become false thus exiting the wile loop. Your first inside the while block reading "t[tIndex].courses_no" again will through everything off because you are reading "coursed_id" into "courses_no" overwriting what you just read and all the next reads are off by one putting the information into the wrong variables.

What I have commented out should be deleted.

I have found that beginners think that they have to use single letters for variable names like: Timetable t[MAXSIZE];. Here "t" can have several different meanings. A variable like: "timeTable" is much easier to read and follow because it says what it is and what its used for. It may seem like it takes more time to type out "timeTable", but not really. A copy and paste can make this easier.

In the for loop to write to "timetable.txt" you might want to what I did with the "student.txt" file.

Now at the point of entering new information.


Is it legal if I do like this?

student[index + 1].id = newId;
student[index + 1].last_name = newFirstName;


Yes it is legal, but not advisable.

At this point the number stored in "index" and "tIndex" would point to the next empty element of the array. Say when you read the "student.csv" file you have ten records stored in your array numbered zero - nine and "index" has a value of ten telling you that you have ten elements of the array used it also means that the next element of the array to be used is element ten which "index" is already set up to use.

What you can do is:
1
2
3
4
5
student[index].no = index + 1;

cout << "Enter new ID: ";
cin >> student[index].id;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

This will allow you to be entering directly into the array and not need the code that follows or the variables that you have defined as "new".

The last entry is for "BOD" and should look like this:
1
2
cout << "Enter dob: ";
getline(cin, student[index++].dob);

The "index++" will increase by one when it is finished using it leaving index equal to the total number of elements in the array and ready for the next entry should you put this in a loop.

When you write to the file out << student[index + 1].no <<. The "+ 1" will be accessing an element of the array that has no information stored in it. What you want here is "- 1" to get to the last element of the array that has information to work with.

I would suggest that you should check the value of "index" and "tIndex" to make sure they are "<= 99" before you try to add past the end of the array and your program crashes.

In a little while I will start testing the program.

Hope that helps and sorry this is so long,

Andy

Edit:
Last edited on
Hello Hello thinhphucvang,

When you created the struct "Timetable" you put all your variables on one line. This is fine, but sometimes this can be helpful:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Timetable
{
	string courses_no;
	string courses_id;
	string lecture_account;
	string class_name;
	string lectures_account;
	string start;
	string end;
	string day;
	string start_hour;
	string end_hour;
	string room;
};

By putting each variable on its own line and putting them in the order in which they are stored in the input file this can help when writing the code to read the input file.

The lines of code that read the "timetable.csv" file those following the part that reads the heading line are missing reading two variables. namely "class_name" and "lectures_account", (the one with the 's'), this is throws the whole read off causing some of the variables to be blank.

When I made the changes it read the file properly and everything is fine.

When I changed the input to put the new information into the array and changed writing to the file to "index -1 " Everything worked.

Hope that helps,

Andy
Until now did I realized that I have to read 5 .csv files with the same format like the students.csv we've discussed.
To read 5 files, do I have to use a for loop with i <5 and rewrite the function with those code?
Hello thinhphucvang,

Yes a for loop would work.

As jlbhas mentioned functions to do some of this work would be a good idea.

Now I have to ask what instructions/directions were you given to work from? This helps to know what needs to be done.

I also have to ask what you know about like:
Functions?
2D arrays or just a 1D array?
vectors?
What IDE/compiler are you using?
And what operating system are you using?

Using system("pause"); I would say Windows.

This will give me an idea of what you can do and use.

Right now what we have started with works once. To use multiple files the program should be restructured. I will work on the changes and see what I come up with.

Hope that helps,

Andy
The project of mine is create a students management system, running on the console.
First, there are 5 file .csv of students' list from 5 different classes (the timetable is also from those 5 classes). My object is to create an menu with 2 options: login and exit.
When logging in, both of the username and the password are the student's ID. And the rest of the project is create a bunch of functions which is not yet touched.
To create the accounts for the students to get access, I must read the whole 5 .csv files of students list and put the students's ID into another file, I would call it accounts.txt.
What we've discussed is just 1 of the files
Last edited on
Pages: 12