How to import data systematically from file?

Okay here is what the file reads


name Test1 Final Avg

John 24 30 27
Lisa 22 26 24
Jake 21 27 23


So far I know how to take in the values if the files does not contain any characters

however since this file contains both integers and characters I dont know what to do.


I want to ready both the Name and the mark and store them in a struct that will act like a folder.


1
2
3
struct Students{
///// I dont know what is best format for the structs
};
Last edited on
Well you could read them into an array of char* or a vector of std::strings (this is probably the easier way to do it), and then parse each line from there.
closed account (zb0S216C)
Within the student structure, marks should have a length of 3 since there's only 3 integer fields per line. 4 is an understandable size if it stored a string, but it doesn't. Also, Name is an array of std::string objects, as far as I can see. Was this intentional?

With the Class structure, Pupil should be an array if it stores multiple instantiations of student. You really should include constructors (and maybe a destructor) for both structures.

As for the importation of your file's data, your file seems fairly linear after the first line. So I would suggest something like 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
void ExtractData(const char *, Class &);

int main()
{
}

void ExtractData(const char *pFileName, Class &rClassI)
{
    if(!pFileName)
        return;

    std::ifstream IStream(pFileName);
    if(!IStream.is_open())
        return;

    student InputBuffer;
    unsigned int uiCounter(0U);
    for(unsigned int Line(0U); Line < (sizeof(rClassI.Pupil) / sizeof(student)); Line++)
    {
        // Note that the above proposition statement will only work if the 'Pupil' array
        // within Class is non-dynamic.
        IStream >> InputBuffer.Name;
        for(uiCounter = 0U; uiCounter < 3U; ++uiCounter)
            IStream >> InputBuffer.marks[uiCounter];
    }
}

Note that this code is untested.

Of course, you'll add better security than I did, but I guess it's a start. Queries? Just ask :)

Wazzak
Last edited on
@Framework

What exactly does the ExtractData function do?

It is kinda confusing.


but on much simpler note if the data were let say something like this

a 1 1
b 4 3
c 2 3

How do I set up a simple script that can read and store each letter and number into different arrays?


If I can get how to do it for that simple data file than I think I think I can do the rest.
Last edited on
Why do you want to store each letter and number into a different array? Assuming your struct of students looks like this:
1
2
3
4
struct student {
        int test, final, average;
        char *name;
}

You could define an array of these like:
 
student students[3];

And then just parse the string, which shouldn't be too hard considering each newline is a new student, and each space comes before the next element.
Last edited on
@ascii

I meant different Array not different Struct, anyways Isnt it easier to put all of the test, final and average marks into one int array?


Secondly can you show me a simple script that reads both numbers and characters and saves them both?
Hopefully this is a bit less confusing. (Probably not, lol)

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
#include <vector>
#include <fstream>
#include <iostream>
#include <cstdlib>

using namespace std;

struct student{
string name;
vector<int> marks; 
};

bool IsInt(string str) {
       for (int i = 0; i < str.length(); i++)
		if (!isdigit(str[i]))
			return false;
	
	return true;
}

int main () {

	int i = 0;
	string tmp;	
	student s[3];
	ifstream fin;
	const int maxGrades = 3;

	fin.open("filename");
	fin >> s[i].name;

	while (fin) {
		for (int j = 0; j < maxGrades; j++) {		
			fin >> tmp;
			if (IsInt(tmp)) 
				s[i].marks.push_back(atoi(tmp.c_str()));
		}
		fin >> s[++i].name;
	}

        return 0;



1
2
3
4
5
6
7
       // prints the students  (any non-integer grades are omitted)
	for (int i = 0; i < 3; i++){
		cout << s[i].name << " ";
		for (int j = 0; j < s[i].marks.size(); j++)	 
			cout << s[i].marks[j] << " ";
		cout << endl;
	}



It will read as many graded as you set the const maxGrades to be. Just make sure you get that number right or it will look funny when you print it out. (it probably won't crash tho)

If non-integer grades are entered in the file the program will not crash but instead omit them and continue on for the most part.

Keep in mind, this code will not read in float or double grades since I am using isdigit to confirm that it is a number.

I would also make the students a vector too but I figured I would keep it as an array so you can see how similar a vector and an array are syntactically. : )
Last edited on
I would use a std::string for the name and int for the numbers:
1
2
3
4
5
6
7
struct student
{
    std::string name;
    int test;
    int final;
    int average;
};

Read in std::string the same way you read in numbers:
1
2
3
4
5
6
7
std::ifstream ifs("mydata.txt");

student s;
if(ifs >> s.name >> s.test >> s.final >> s.average)
{
    // s was read successfully
}
@icethatJaw

That script doesnt seem to do anything or show anything when I asked it to show the data is retrieved.
what do you mean? Did you insert your filename, compile it, and place the executable in the same directory as the file?

And it only works for the format

John 24 30 27
Lisa 22 26 24
Jake 21 27 23

If that first line in actually in the file you will need to extract or ignore it.
@IceThatJaw

well this is how i modified it

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
#include <vector>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <string>
#include <stdio.h>
#include <string.h>


#include <stdlib.h>

#include <ctype.h>


using namespace std;

struct student{
string name;
vector<int> marks; 
};

bool IsInt(string str) {
       for (int i = 0; i < str.length(); i++)
		if (!isdigit(str[i]))
			return false;
	
	return true;
}

int main () {

	int i = 0;
	string tmp;	
	student s[3];
	ifstream fin;
	const int maxGrades = 3;

	fin.open("dat.txt");
	fin >> s[i].name;

	while (fin) {
		for (int j = 0; j < maxGrades; j++) {		
			fin >> tmp;
			if (IsInt(tmp)) 
				s[i].marks.push_back(atoi(tmp.c_str()));
		}
		fin >> s[++i].name;
	}


cout<<s[0].name;   //  here is where I ask it to show me the names it recieved
cout<<s[1].name;  //

system("pause");
        return 0;
        }




Doesnt get me anything, Am I using it wrongly?
Now that I look at this, I think you should look away in disgust. I am also pretty new to C++ and I just wanted to give you a quick answer.

Do not use atoi if you can avoid it. It isn't even C++ and your professor will not be impressed. My professors wouldn't even grade me if I used it. I took a little time and wrote a much better algorithm for reseting the stream if it fails.

By now , you know that trying to read in an non-integer data into an integer will cause the stream to the fail. If it is a decimal for instance, it will read until it hits the . and the stream will fail. If you try to read in 23dhfbg it will read until it hits the d and the stream will fail.

Well, you can use this to your advantage. Check out this simple (sorta simple) algorithm I just came up with. It will read in any integers, as long as they are at the beginning of the word. So 23hdgd will be read in as 23, 23.25 will be read in as 23, but dhdh23 will be ignored.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	char buff;
	int tmp;
        ifstream fin;	
	fin.open("filename-here");
	
	fin >> tmp;
	while (!fin.eof()) {
		if (fin.fail()) {
			fin.clear();
			buff  = fin.get();		
			while (buff != ' ' and buff != '\n')
				buff  = fin.get();
		}
		else
			// store the integer or reverse the if statement to "if (!fin.fail()) - store the data" 
                        // and store only 100% valid data (Probably a good idea)	
		fin >> tmp;
	}



Now if you play around with this you can tweak it to ignore ANY data that causes the stream to fail if you so choose. Using this algorithm will allow you to avoid converting chars or strings to integers which is never 100% guaranteed, or so I have read.
Last edited on
@Ice that Im not really sure how I can modify that to use on the text file.

To me the integer part doesn't really matter and is of little significance for now, what I was looking for was something that would read anything like

a 1 2 3
b 2 3 4


and get me a and b in an string array and all the numbers in a int array


Like I said If I can master that then the rest should be no problem.
For the second time, read each line into an std::string and then just parse it to take out the data you want.
Topic archived. No new replies allowed.