Taking Sets of Data from File

So I have a file with information (such as name, age, etc.) about different players, and I somehow need to move that into my program, but keep it grouped by each player. Problem is, I have absolutely no idea how to do that.

Here is 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
#include <iostream>
#include <fstream>
#include <iomanip>
#define FILE_IN "packers.dat"
using namespace std;

struct playerinfo
{
       string playernum, playername, playerpos, playercol;
       int height, weight, age, exp;
}team [53];

int main()
{
    char junk, exit;
    float avheight, avweight;
    int teamsize = 53;
    cout << "This is the 2013-2014 Green Bay Packers team roster:";
    cout << endl;
    cout << endl;
    ifstream input;
    input.open (FILE_IN, ios::in);
    
    while (!input.eof())//Here's where I completely lose any knowledge of how to do this
    {
          ; 
          input.get (junk) //I do however, feel like this has to be there, but I could be wrong
          ;
    }
    
    input.close();

    writeplayerdata (teamsize, team, avheight, avweight);
}

void writeplayerdata (int teamsize, playerinfo team[], float avgheight, float avgweight)
{
     int teamcounter;
     for (teamcounter = 0; teamcounter = teamsize; ++teamcounter)
     {
         cout << setw(3) << team[teamcounter].playernum << setw(28); 
         cout << team[teamcounter].playername << setw(6);
         cout << team[teamcounter].playerpos << setw(5); 
         cout << team[teamcounter].height << setw(6);  
         cout << team[teamcounter].weight << setw(5) << team[teamcounter].age; 
         cout << setw(4) << team[teamcounter].exp << setw(28);
         cout << team[teamcounter].playercol;
         cout << endl;
         cout << endl;
     }
     
     cout << "The average height of the team is " << avgheight << "inches.";
     cout << endl;
     cout << "The average weight of the team is " << avgweight << "pounds.";
}
Depends on how your input data is formatted. If it is written out in a single line like writeplayerdata(), you could use an fstream and read it in almost exactly the same way as you did the output.

http://www.cplusplus.com/doc/tutorial/files/
Here's a simple example, involving two addresses stored in a text file. Each line of each address is applied to it's own array position before output.
The input file:
Steven Seagal
1234 Post Drive
Ventura, CA 90734

Adam Sandler
356 Golf Street
Calabasas, CA 92136
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
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
    string address1[3],address2[3];

    fstream infile;
    infile.open("data.txt");
    if (!infile)
    {
        cout<<"Error reading file!";
        return 0;
    }
    else
    {
        cout<<"Reading from file...\n";

        //read data in for first address and output it
        for (int i=0; i<3; i++)
        {
            getline(infile,address1[i]);
            cout<<address1[i]<<endl;
        }
        cout<<endl;
        //read data in for second address and output, ignoring blank line
        for (int i=0; i<3; i++)
        {
            getline(infile,address2[i]);
            if (address2[i]=="")
            {
                i--;//repeat array position when encountering blank line
            }
            else
                cout<<address2[i]<<endl;
        }
    }
    return 0;
}

My output looks just like my input file, other than the fact that it says "Reading from file..." above it.
If, however, you wish to store each value individually instead of each line, I recommend looking at this thread here:
http://www.cplusplus.com/forum/beginner/121657/
Last edited on
CplusplusAcolyte, that's not quite what I am looking for. In the program and the article, you have each line being read in individually. I would like to keep the program so I still use the struct playerinfo that I already have. That, and I really don't want to use a different loop for each player, considering I am working with 53 of them. Yulingo, I know what you are doing and I think it'll work, but does it work when the file format is like this? (What is in parentheses is what each line corresponds to):

87 (playernum)
Phil (playername)
Forward (playerpos)
60 (height)
140 (weight)
27 (age)
Harvard (playercol)
3 (exp)
Last edited on
I offered the code sample because it had been recently worked out in another thread, but as you say, it differs from the circumstances involved here.

Still, I think a solution can be adapted from the above link, which demonstrates how to work with individual words from the file. If you read each word in individually, store them in temp variables, and then call the structure the way you call a function, perhaps the values read in could be passed to the structure?

I'll look into this, as I want to better my understanding of how structures work. I believe I spotted a typo in your code, however; check line 39 and try changing teamcounter = teamsize to teamcounter < teamsize within your for loop.
Last edited on
Upon further research, it looks like the proper way to make an array of structures would be to first declare the structure as an array, not in the structure, but in main. Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct playerinfo
{
       string playernum, playername, playerpos, playercol;
       int height, weight, age, exp;
};

int main()
{
int teamsize=53;
playerinfo team[teamsize];//an array of playerinfo based on teamsize
team[0].age=35;//example of structure access
return 0;
}

Make the necessary changes and also change your while !eof loop to if (!input) return 1;, and take a closer look at your for loop on line 39 as I mentioned above, and let us know how it goes. I think you are going to need to convert strings to ints to assign the int values properly when reading them in from the file, and have your loop know when and when not to do that based on the sequence of values in the file.

It also looks like you need a variable to hold each structure being read in and it won't pick it up on it's own, can't use pointers to point to each structure and automatically be parsed by the function. Instead I think a variable is given the values (all of them) within a structure, and the values must be parsed from it, and in order to assign values, we have to get a loop to read them in from the file one by one and assign them to a structure. Then an outer loop can do the same for each successive structure, based on the value of teamsize.
Last edited on
Ok, I've figured a bit more out. Here's some code that should nudge you in the right direction.
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
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

struct playerinfo
{
       string playernum, playername, playerpos, playercol;
       int height, weight, age, exp;
};

playerinfo writeplayerdata ()
{
    playerinfo team[53];//declare structure variable team
    team[0].height=10;//example of structure access
    return team[0];
}

int main()
{
    string playerFields[8];//store 8 strings
    int teamsize=53;//sets quantity of teammembers

    fstream input;
    input.open("packers.dat");//load file in
    if (!input)
    {
        cout<<"Error accessing packers.dat";
        return 1;
    }
    else
    {
        playerinfo team[teamsize];
        team[0]=writeplayerdata();
        cout<<team[0].height;
    };
}

If you can get your writeplayer data to contain and execute a loop while assigning values to fields in the appropriate order, and converting to int when needed, you should be good, but you also need to parse the individual strings from the file beforehand.
Last edited on
Ok, I'm on the right track. While it's not a full solution, this code demonstrates how to pass your structure to a function for modification when the structure is an array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

struct playerinfo
{
       string playernum, playername, playerpos, playercol;
       int height, weight, age, exp;
};

playerinfo changeStats(playerinfo player[], int member)
{   //access specific player and alter stats
    player[member].playernum="87";
    player[member].playername="Phil";
    return player[member];
};

int main()
{
    playerinfo player[53];//declare players
    player[0]=changeStats(player,0);
    cout<<player[0].playername<<","<<player[0].playernum;
}

Because each line of your input file is it's own field, it shouldn't be difficult to use getline to store 8 strings in an array before applying them via function (converting to int when needed), and then repeat for each player.
Last edited on
Ok, I got the solution. As long as each player has 8 fields to be assigned to them, and they are stored just like the first player's info and in the same sequence, this will work. You just need another loop that iterates the function that changes stats for each player, and uses it's counter to determine which player is modified. If there is a blank line between each player's stats, we will have to get our function to account for that though.
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
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

struct playerinfo
{
       string playernum, playername, playerpos, playercol;
       int height, weight, age, exp;
};

playerinfo changeStats(playerinfo team[], int member, string playerData[])
{   //access specific player and alter stats
    for (int i=0;i<8;i++)
    {
        if (i==0)
            team[member].playernum=playerData[i];
        else if (i==1)
            team[member].playername=playerData[i];
        else if (i==2)
            team[member].playerpos=playerData[i];
        else if (i==3 || i==4 || i==5 || i==7)
        {   //convert to int before adding to structure when applicable
            int x;//int to hold converted values
            stringstream convertor;//used for conversion
            convertor<<playerData[i];//reads in strings in playerData
            convertor>>x;//adds converted value to x
            if (i==3)
                team[member].height=x;
            else if (i==4)
                team[member].weight=x;
            else if (i==5)
                team[member].age=x;
            else
                team[member].exp=x;
        }
        else
            team[member].playercol=playerData[i];
    }
    return team[member];//return modified team member
};

int main()
{
    string playerData[8];//used to store 8 values for each player
    playerinfo team[53];//declare 53 players

    fstream input;
    input.open("packers.dat");//load file in

    if (!input)
    {
        cout<<"Error loading packers.dat!";
        return 1;
    }
    else
    {   string word;
        for (int i=0;i<8;i++)
        {
            getline(input,word);//grab each field and store in word
            playerData[i]=word;//assign each word to playerData
        }
    input.close();//close input file
    //change 1st player based on file data read in
    team[0]=changeStats(team,0,playerData);
    //output player's info to confirm change
    cout<<"Player Number:\t"<<team[0].playernum<<endl;
    cout<<"Player Name:\t"<<team[0].playername<<endl;
    cout<<"Player Pos:\t"<<team[0].playerpos<<endl;
    cout<<"Player Height:\t"<<team[0].height<<endl;
    cout<<"Player Weight:\t"<<team[0].weight<<endl;
    cout<<"Player Age:\t"<<team[0].age<<endl;
    cout<<"Player Col:\t"<<team[0].playercol<<endl;
    cout<<"Player Exp:\t"<<team[0].exp<<endl;
    return 0;
    }
}
Player Number:     87
Player Name:       Phil
Player Pos:        Forward
Player Height:     60
Player Weight:     140
Player Age:        27
Player Col:        Harvard
Player Exp:        3

If you make your writeplayerdata function more like my changeStats function, it should do the job.
Last edited on
Ok, here is the full solution. Taking my packers.dat file, I added another player with a blank line between the two, populated both player's stats, and outputted them. If you have no blank line between each player's stats, you can remove the if statement that repeats the getline command when encountering a blank line.

All you have to do is alter your loop on line 64 to populate 53 player's data instead of 2, and remove the if statement and redundant getline command on lines 69 and 70 if you have no blank line between player's stats.
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
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

struct playerinfo
{
    string playernum, playername, playerpos, playercol;
    int height, weight, age, exp;
};

playerinfo changeStats(playerinfo team[], int member, string playerData[])
{
    //access specific player and alter stats
    for (int i=0; i<8; i++)
    {
        if (i==0)
            team[member].playernum=playerData[i];
        else if (i==1)
            team[member].playername=playerData[i];
        else if (i==2)
            team[member].playerpos=playerData[i];
        else if (i==3 || i==4 || i==5 || i==7)
        {
            //convert to int before adding to structure when applicable
            int x;//int to hold converted values
            stringstream convertor;//used for conversion
            convertor<<playerData[i];//reads in strings in playerData
            convertor>>x;//adds converted value to x
            if (i==3)
                team[member].height=x;
            else if (i==4)
                team[member].weight=x;
            else if (i==5)
                team[member].age=x;
            else
                team[member].exp=x;
        }
        else
            team[member].playercol=playerData[i];
    }
    return team[member];//return modified team member
};

int main()
{
    string playerData[8];//used to store 8 values for each player
    playerinfo team[53];//declare players and initialize stats

    fstream input;
    input.open("packers.dat");//load file in

    if (!input)
    {
        cout<<"Error loading packers.dat!";
        return 1;
    }
    else
    {
        string word;

        //change player based on file data read in
        for (int j=0; j<2; j++)
        {
            for (int i=0; i<8; i++)
            {
                getline(input,word);//grab each field and store in word
                if (word=="")//skip blank line between player's stats
                    getline(input,word);
                playerData[i]=word;//assign each word to playerData
            }
            team[j]=changeStats(team,j,playerData);
        }
        input.close();//close input file
        //output both player's info to confirm change
        for (int i=0; i<2; i++)
        {
            cout<<"Player Number:\t"<<team[i].playernum<<endl;
            cout<<"Player Name:\t"<<team[i].playername<<endl;
            cout<<"Player Pos:\t"<<team[i].playerpos<<endl;
            cout<<"Player Height:\t"<<team[i].height<<endl;
            cout<<"Player Weight:\t"<<team[i].weight<<endl;
            cout<<"Player Age:\t"<<team[i].age<<endl;
            cout<<"Player Col:\t"<<team[i].playercol<<endl;
            cout<<"Player Exp:\t"<<team[i].exp<<endl<<endl;
        }
        return 0;
    }
}
Player Number:     87
Player Name:       Phil
Player Pos:        Forward
Player Height:     60
Player Weight:     140
Player Age:        27
Player Col:        Harvard
Player Exp:        3

Player Number:     30
Player Name:       John
Player Pos:        Fullback
Player Height:     60
Player Weight:     250
Player Age:        23
Player Col:        Alabama
Player Exp:        8

Lastly, change your output loop on line 77 from 2 to 53 and it will output all 53's player's stats assuming you already have them in your file.
Last edited on
Topic archived. No new replies allowed.