Not sure why this isn't reading from a file correctly

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
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

class Inventory {
private:
	string desc;	// Description
	int qty;		// Quantity
	float wSale;	// Wholesale cost
	float rPrice;	// Retail price
	string date;	// Date added to inventory
public:
	Inventory();

	void setDesc(string);
	void setQty(int);
	void setWSale(float);
	void setRPrice(float);
	void setDate(string);

	string getDesc() const;
	int getQty() const;
	float getWSale() const;
	float getRPrice() const;
	string getDate() const;
};

Inventory::Inventory()
{
	desc = "";
	qty = 0;
	wSale = 0.0;
	rPrice = 0.0;
	date = "";
}

void Inventory::setDesc(string d)
{
	desc = d;
}
void Inventory::setQty(int q)
{
	qty = q;
}
void Inventory::setWSale(float ws)
{
	wSale = ws;
}
void Inventory::setRPrice(float rp)
{
	rPrice = rp;
}
void Inventory::setDate(string da)
{
	date = da;
}
string Inventory::getDesc() const
{
	return desc;
}
int Inventory::getQty() const
{
	return qty;
}
float Inventory::getWSale() const
{
	return wSale;
}
float Inventory::getRPrice() const
{
	return rPrice;
}
string Inventory::getDate() const
{
	return date;
}

void displayRecord(fstream& File)
{
	Inventory record;

	string desc;
	int qty;
	float wSale;
	float rPrice;
	string date;
	string tempSTR;

	long recNum;

	// Open the file.
	File.open("inventory.txt", ios::in | ios::beg);
	if (File.fail()) {	//if File fails to open display error message
		cerr << "Error opening file." << endl;
		exit(0);
	}
	// Get the record number from the user.
	cout << "\nEnter the record number of the item: ";
	cin >> recNum;
	if (recNum < 1)
		recNum = 1;
	recNum--;

	// Seek to the record.
	File.seekg(recNum * sizeof(record), ios::beg);

	getline(File, tempSTR);
	stringstream stream(tempSTR);
	getline(stream, desc, ',');
	stream >> qty >> wSale >> date >> rPrice;

        //update record;
	record.setDesc(desc);
	record.setQty(qty);
	record.setWSale(wSale);
	record.setRPrice(rPrice);
	record.setDate(date);

	File.close();

	// Display the record.
	cout << "Description: " << record.getDesc() << endl;
	cout << "Quantity: " << record.getQty() << endl;
	cout << "Wholesale cost: " << record.getWSale() << endl;
	cout << "Retail price: " << record.getRPrice() << endl;
	cout << "Date: " << record.getDate() << endl << endl;
}

int main()
{
	fstream File;
	displayRecord(File);
}

Hello. The issue that I'm having is that when I run the code, it displays fine if I input 1, the result is what is expected and prints the first line of the text. If I input 2, the result is out of expectation and is weird. I know that it isn't updating the class wrong, so I think it's most likely the seekg function in line 108 that is causing the issue, but I'm not sure what's wrong with it. I'm pretty sure that it is in the right format...

Also, this is the text file that I'm reading from:
1
2
PC Parts,24	100	12/14/2017	90
Art Poster,50	1000	01/21/2004	900


I'm not sure if this matters, but this is the format I used to output into the file in another function. I didn't want to post a full code because I'm not sure if people would appreciate that so I made this as short as I could.
 
File << desc << ',' << qty << "\t" << wSale << "\t" << date << "\t" << rPrice << "\r\n";

Thanks for reading!
Last edited on
seekg will not work for text files. It's more suitable for binary files where each record takes up the same amount of bytes.
Is there a function that I can use to achieve the same results as using seekg for a text file?
Last edited on
If you want to skip to a specific line in a file you might want to call getline (or stream.ignore(some_very_large_value, '\n')) in a loop.

1
2
3
4
for (int i = 0; i < recNum; ++i)
{
	stream.ignore(numeric_limits<streamsize>::max(), '\n');
}
Last edited on
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
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

class Inventory {
private:
	string desc;	// Description
	int qty;		// Quantity
	float wSale;	// Wholesale cost
	float rPrice;	// Retail price
	string date;	// Date added to inventory
public:
	Inventory();

	void setDesc(string);
	void setQty(int);
	void setWSale(float);
	void setRPrice(float);
	void setDate(string);

	string getDesc() const;
	int getQty() const;
	float getWSale() const;
	float getRPrice() const;
	string getDate() const;
};

Inventory::Inventory()
{
	desc = "";
	qty = 0;
	wSale = 0.0;
	rPrice = 0.0;
	date = "";
}

void Inventory::setDesc(string d)
{
	desc = d;
}
void Inventory::setQty(int q)
{
	qty = q;
}
void Inventory::setWSale(float ws)
{
	wSale = ws;
}
void Inventory::setRPrice(float rp)
{
	rPrice = rp;
}
void Inventory::setDate(string da)
{
	date = da;
}
string Inventory::getDesc() const
{
	return desc;
}
int Inventory::getQty() const
{
	return qty;
}
float Inventory::getWSale() const
{
	return wSale;
}
float Inventory::getRPrice() const
{
	return rPrice;
}
string Inventory::getDate() const
{
	return date;
}

void changeRecord(fstream &File)
{
	Inventory record;

	string desc;
	int qty;
	float wSale;
	float rPrice;
	string date;
	string tempSTR;

	long recNum;				//user choicer record number
	bool recNumBeyond = false;	//if record number is beyond number of records available

								// Open the file.
	File.open("inventory.txt", ios::out | ios::in | ios::beg);
	if (File.fail()) {	//if File fails to open display error message
		cerr << "Error opening file." << endl;
		exit(EXIT_FAILURE);
	}

	//get number of lines the file has
	int lineCount = count(istreambuf_iterator<char>(File),
		istreambuf_iterator<char>(), '\n');

	//clear and go to beginning
	File.clear();
	File.seekg(0L, ios::beg);

	//Validation if user chooses a record that is beyond
	do {
		cout << "\nEnter the record number of the item: ";
		cin >> recNum;
		if (recNum < 1)
			recNum = 1;
		recNum--;

		if (recNum > lineCount - 1)
			cout << "Oops! There are a total of " << lineCount << " records on file.\n please re-try" << endl;
	} while (recNum > lineCount - 1);


	// Seek to the record.
	for (int i = 0; i < recNum; ++i) //This his how I implemented Peter87's code
	{
		File.ignore(numeric_limits<streamsize>::max(), '\n');
	}


	getline(File, tempSTR);
	stringstream stream(tempSTR);
	getline(stream, desc, ',');
	stream >> qty >> wSale >> date >> rPrice;

	record.setDesc(desc);
	record.setQty(qty);
	record.setWSale(wSale);
	record.setRPrice(rPrice);
	record.setDate(date);


	// Display the record.
	cout << "Description: " << record.getDesc() << endl;
	cout << "Quantity: " << record.getQty() << endl;
	cout << "Wholesale cost: " << record.getWSale() << endl;
	cout << "Retail price: " << record.getRPrice() << endl;
	cout << "Date: " << record.getDate() << endl << endl;

	// Get new data.
	cout << "Enter the new data:\n";

	// Get the description.
	cout << "Description: ";
	cin.ignore();
	getline(cin, desc);

	// Get the quantity.
	cout << "Quantity: ";
	cin >> qty;
	while (qty < 0)
	{
		cout << "Enter a positive value, please: ";
		cin >> qty;
	}

	// Get the wholesale cost.
	cout << "Wholesale cost: ";
	cin >> wSale;
	while (wSale < 0)
	{
		cout << "Enter a positive value, please: ";
		cin >> wSale;
	}

	// Get the retail price.
	cout << "Retail price: ";
	cin >> rPrice;
	while (rPrice < 0)
	{
		cout << "Enter a positive value, please: ";
		cin >> rPrice;
	}

	// Get the date added to inventory.
		cout << "Date added to inventory (MM/DD/YYYY): ";
		cin.ignore();
		getline(cin, date);

		//clear and go to beginning
		File.seekp(0, ios::beg);

		// Seek to the record.
		for (int i = 0; i < recNum; ++i)
		{
			File.ignore(numeric_limits<streamsize>::max(), '\n');
		}

		//Output updated data
		File << desc << ',' << qty << "\t" << wSale << "\t" << date << "\t" << rPrice << "\r\n";

		// Close the file.
		File.close();
}

int main()
{
	fstream File;
	changeRecord(File);
}


I had another function in the original code that allowed me to change a data. Peter87's code solved my issue with getting to the right line in a text file. Thank you Peter87... Right now I'm having an issue with writing new data to the line. The line in question is 199.
Last edited on
The records in the file are of variable length. That means that updating a record in-place will only be possible if the new record is identical in length. Effectively that constrains the design to using fixed-length records.

One alternative is to read all the records from the file into a container, such as a std::vector. Make the changes to the record(s) in the vector. When finished, write entire contents of the container (vector) back to the file.
Those kind of errors can be detected early when you develop correctly and look for mistakes within your code.
You have a lot of tutorials on the web to help you do that. It also looks like you can use some programs to help you do that.
I got an advise once to use Checkmarx to detect vulnerabilities in the code, you can try it out.
Good luck
Thank you @Chervil! Thanks for letting me know what was wrong with it, and in doing so I was able to figure out what I neede to do. I could have used vectors but in honestly I don't know how to use them... yet. But I plan on learning soon. I on the other hand just decided to update the whole file instead of updating individual lines. That's obviously not efficient but it's what I'll have to do for now. Thanks for the help! I have learned many things in the process.
Registered users can post here. Sign in or register to post.