# [C++] Reading things from files.



## dmneoblade (Apr 15, 2004)

Ok, I am trying to write a few programs, and to do so, I need to read misc things from files. Could someone please dump a few code snippits here on how to:
1: Read an integer from a file
2: Read data separated by ;; into an array
ie:
file.txt
1;;2
3;;4
turns into an array like
array[0][0] == 1
array[0][1] == 2
array[1][0] == 3
array[1][1] == 4


----------



## Shadow2531 (Apr 30, 2001)

Readfile example


```
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>

using namespace std;

int main() {
    string filename = "test.txt";
    ifstream textfile (filename.c_str());
    if (!textfile) {
        cout << endl << "Could not open " << filename << endl;
        exit(EXIT_FAILURE);
    }
    string readline;
    while(!textfile.eof()) {
        getline(textfile,readline);
        cout << readline << endl;
    }
}
```
Read and split up (if only one instance of ;


```
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>

using namespace std;

int main() {
    string filename = "test.txt";
    ifstream textfile (filename.c_str());
    if (!textfile) {
        cout << endl << "Could not open " << filename << endl;
        exit(EXIT_FAILURE);
    }
    string readline;
    while(!textfile.eof()) {
        getline(textfile,readline);
        if (readline.find(";;") != string::npos) {
            cout << readline.substr(0,readline.find(";;")) << endl 
                 << readline.substr(readline.rfind(";;") + 2 ) << endl;
        }
    }
}
```


----------



## dmneoblade (Apr 15, 2004)

Ah... let me try to clear this up a bit...
I want to read lines from a file such as:

```
1;;5;;Short Sword;;500
6;;10;;Gem;;3000
```
becomes an array like

```
array[0][1] == 5
array[1][2] == Gem
```
make sense?


----------



## Shadow2531 (Apr 30, 2001)

Yes.

An array is not ideal though since you don't know what the size of the array needs to be. It can be determined though, but a vector would be better suited.


----------



## Shadow2531 (Apr 30, 2001)

Here's a modified version of a string tokenizer I wrote for a task.


```
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <fstream>

using namespace std;

void remove_second_column(string& readline, vector<string>& tokens, const string& delimiter) {
    string::size_type lastPos = readline.find_first_not_of(delimiter, 0); 
    string::size_type pos = readline.find_first_of(delimiter, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(readline.substr(lastPos, pos - lastPos));
        lastPos = readline.find_first_not_of(delimiter, pos);
        pos = readline.find_first_of(delimiter, lastPos);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 2 ) {
        const string filename = argv[1];
        ifstream input(filename.c_str());
        if (!input) {
            cout << endl << "Error opening input file" << endl;
            exit(EXIT_FAILURE);
        }
        const string outputname = filename + ".fixed.csv";
        ofstream fixer(outputname.c_str());
        if (!fixer) {
            cout << endl << "Error opening output file" << endl;
            exit(EXIT_FAILURE);
        }
        string readline;
        vector<string> tokens;
        const string delimiter = ";;";
        while (!input.eof()) {
            getline(input,readline);
            if (readline.find(delimiter.c_str()) != std::string::npos && readline.find(delimiter.c_str()) != readline.find_last_of(delimiter.c_str()) ) {
                remove_second_column(readline,tokens,delimiter);
                copy(tokens.begin(),tokens.end() - 1 , ostream_iterator<string>(fixer," ")) ;
                copy(tokens.end() - 1 ,tokens.end() , ostream_iterator<string>(fixer,"\n")) ;
                tokens.clear();
            }
        }
    }
    if (argc != 2) {
        cout << endl << "Usage: fixer file" << endl;
    }
}
```
take your text and drag it on the exe. It will splitup the different entries separated by ;; and output them to a new file separated by a space.

Now that is not what you need to do, but the code shows you how to split up the entries and shove them into a vector. A vector is very much like an array except a vector's size is dynamic.

Say if *fire* is a vector.

fire.at(0) is the first value, fire.at(1) is the second etc.

Now for that code, you can get rid of the 2 copy lines and the tokens.clear() line to shove everything in the vector so that when it's done reading the file, all the entries will be stored in the vector.

There's a much simpler way to do the tokenizer function, but it uses the Boost regex library. If you have it, then I can show you that way.

Also since the vector will have a size that you can check, you could probably dump all the values into an array with a loop, but you'll have to know how many columns you want to split the array up into, so you can determine the proper size of the array. Also, if one line in the text file doesn't have a column that another has, you'll have to take that in consideration. Arrays are evil.

Just to be clear on stuffing all of it in the vector and then doing something with it..


```
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <fstream>

using namespace std;

void let_us_tokenize(string& readline, vector<string>& tokens, const string& delimiter) {
    string::size_type lastPos = readline.find_first_not_of(delimiter, 0); 
    string::size_type pos = readline.find_first_of(delimiter, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(readline.substr(lastPos, pos - lastPos));
        lastPos = readline.find_first_not_of(delimiter, pos);
        pos = readline.find_first_of(delimiter, lastPos);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 2 ) {
        const string filename = argv[1];
        ifstream input(filename.c_str());
        if (!input) {
            cout << endl << "Error opening input file" << endl;
            exit(EXIT_FAILURE);
        }
        const string outputname = filename + ".fixed.csv";
        ofstream fixer(outputname.c_str());
        if (!fixer) {
            cout << endl << "Error opening output file" << endl;
            exit(EXIT_FAILURE);
        }
        string readline;
        vector<string> tokens;
        const string delimiter = ";;";
        while (!input.eof()) {
            getline(input,readline);
            if (readline.find(delimiter.c_str()) != std::string::npos && readline.find(delimiter.c_str()) != readline.find_last_of(delimiter.c_str()) ) {
                let_us_tokenize(readline,tokens,delimiter);
            }
        }
        copy(tokens.begin(),tokens.end() - 1 , ostream_iterator<string>(fixer," ")) ;
        copy(tokens.end() - 1 ,tokens.end() , ostream_iterator<string>(fixer,"\n")) ;
    }
    if (argc != 2) {
        cout << endl << "Usage: fixer file" << endl;
    }
}
```
You can also use a loop instead of those copy lines.


```
for (unsigned int check = 0; check < tokens.size(); check++) {
    fixer << tokens.at(check) << endl;
}
```
All of this should give you some ideas.


----------



## Shadow2531 (Apr 30, 2001)

O.K. here's an example that involves an array.


```
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <fstream>

using namespace std;

void split(string& readline, vector<string>& tokens, const string& sep) {
    string::size_type lastPos = readline.find_first_not_of(sep, 0); 
    string::size_type pos = readline.find_first_of(sep, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(readline.substr(lastPos, pos - lastPos));
        lastPos = readline.find_first_not_of(sep, pos);
        pos = readline.find_first_of(sep, lastPos);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 2) {
        const string filename = argv[1];
        ifstream textfile(filename.c_str());
        if (!textfile) {
            cout << endl << "Error opening " << filename << endl;
            exit(EXIT_FAILURE);
        }
        string readline;
        const string sep = ";;";
        vector<string> tokens;
        while (!textfile.eof()) {
            getline(textfile,readline);
            if (readline.find(sep.c_str()) != string::npos && 
            readline.find(sep.c_str()) != readline.find_last_of(sep.c_str()) ) {
                split(readline,tokens,sep);
            }
        }
        const int arr_row_size = tokens.size() / 2;
        string my_array[arr_row_size][2];
        int y = 1;
        int z = 0;
        for (int row = 0; row < arr_row_size; row++) {
            my_array[row][0] = tokens.at(row + z);
            my_array[row][1] = tokens.at(row + y);
            y++;
            z++;
        }
        for (int x = 0 ; x < arr_row_size ; x++) {
            cout << my_array[x][0] << " " << my_array[x][1] << endl;
        }
    }
}
```
You can save that one as array.cpp

Usage is array.exe file

Create test.txt with the following

1;;2
3;;4
5;;6
7;;8

Make it perfect. No extra spaces in each line.

Then run *array test.txt*

What the code does is split up the numbers and dynamically creates an array based on the size of the vector and shoves them in an array like you want.

The catch is, you need to specify in the code, the number of columns the array is going to have. The code for the loop that shoves the contents in the array also reflects the the number of columns needed.

For this example, I made the code for 2 columns.

It is possible to determine the line with the most split up entries and use that number to dynamically set the columns of the array etc. You would also have to improve the loop code and account for entries that are blank, plus fill empty positions in the array with " ".

There really is no reason to use an array. I could have just used the vector and a simple loop to do the same thing. Just consider the "Column" deal, a thing in your head.


```
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <fstream>

using namespace std;

void split(string& readline, vector<string>& tokens, const string& sep) {
    string::size_type lastPos = readline.find_first_not_of(sep, 0); 
    string::size_type pos = readline.find_first_of(sep, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(readline.substr(lastPos, pos - lastPos));
        lastPos = readline.find_first_not_of(sep, pos);
        pos = readline.find_first_of(sep, lastPos);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 2) {
        const string filename = argv[1];
        ifstream textfile(filename.c_str());
        if (!textfile) {
            cout << endl << "Error opening " << filename << endl;
            exit(EXIT_FAILURE);
        }
        string readline;
        const string sep = ";;";
        vector<string> tokens;
        while (!textfile.eof()) {
            getline(textfile,readline);
            if (readline.find(sep.c_str()) != string::npos && 
            readline.find(sep.c_str()) != readline.find_last_of(sep.c_str()) ) {
                split(readline,tokens,sep);
            }
        }
        int column = 0;
        for (unsigned int x = 0 ; x < tokens.size() ; x++) {
            cout << tokens.at(x) << " ";
            column++;
            if (column == 2) {
                cout << endl;
                column = 0;
            }
        }
    }
}
```
vectors > arrays.

Just thought I'd be a sport and give an array example.


----------



## dmneoblade (Apr 15, 2004)

looks a bit complicated... but THANKS!
I'll get to work on learning this right away...
just to think, two years ago I started learning "a little programming, so I could make programs for DnD".


----------



## Shadow2531 (Apr 30, 2001)

I should have provided a basic vector example first.


```
#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main() {
    vector<string> example;
    example.push_back("This");
    example.push_back("is");
    example.push_back("a");
    example.push_back("vector");
    example.push_back("example.");
    cout << example.at(0) << " " << example.at(1) << " " 
         << example.at(2) << " " << example.at(3) << " " 
         << example.at(4) << endl;
}
```


----------



## dmneoblade (Apr 15, 2004)

AH! That ties it together. Just one thing... to read numbers, do I change it from vector<string> to vector<int> of vector<float>


----------



## Shadow2531 (Apr 30, 2001)

Yep you can do that.

If you are reading from a file, you'll want it to still be a string. You can then get rid of all non numbered characters and convert to int if you need to.


----------



## dmneoblade (Apr 15, 2004)

how do I do that? Been tyring to figure that one out for a long time...


----------



## Shadow2531 (Apr 30, 2001)

convert a string to int/float/double etc?

I'll post an example when I get a chance.


----------



## Shadow2531 (Apr 30, 2001)

Here's a quick example.


```
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

int main() {
    string test = "4dfdsfsl";
    stringstream ss(test);
    int bla;
    ss >> bla;
    cout << bla + 5 << endl;
}
```
It can get more complicated than that, but that will get you started.

If you want the non-stl way, you can do

string a="321"
int b = atoi(a.c_str());


----------



## dmneoblade (Apr 15, 2004)

what are the benefits of using/not using the STL?


----------



## Shadow2531 (Apr 30, 2001)

AFAIK atoi() isn't guaranteed to be supported by every compiler/(set of headers), which is why it's better to use stringstream.

If no one is going to be compiling your code then I don't think you have to worry.

atoi() BTW lives in <cstdlib>


----------



## dmneoblade (Apr 15, 2004)

New thing:
how can I figure out how many delimiters there were in a line of the file?
I am trying to take two input variables (basically an X and a Y), and get the data from the file.
Remember: this started off as an array. If you need source code, just tell me, and I will post it somewhere.


----------



## Shadow2531 (Apr 30, 2001)

When I get a chance, I'll come up with an example.

A hint though:

You can use a loop, find("delimeter") and compare it with find_last_of("delimeter") and increment a variable when they are not the same.


----------



## Shadow2531 (Apr 30, 2001)

Given: ;; = the delimiter


```
#include <iostream>
#include <string>

using namespace std;

int main() {
    string t = "11;;22;;33;;44;;55;;66;;77";
    if (t.find(";;") != string::npos) {
        if (t.find(";;") == t.find_last_of(";;") - 1 ) {
            cout << "# of delimiters = 1" << endl;
        }
        else {
            string::size_type lastPos = t.find_first_not_of(";;", 0); 
            string::size_type pos = t.find_first_of(";;", lastPos);
            int count = 0;
            while (string::npos != pos || string::npos != lastPos) {
                lastPos = t.find_first_not_of(";;", pos);
                pos = t.find_first_of(";;", lastPos);
                count++;
            }
            cout << "# of delimiters = " << count - 1 << endl;
        }
    }
    else {
        cout << "# of delimiters = 0" << endl;
    }
}
```
Keep changing the value of *t* to test it. If the string has a trailing delimiter, that delimiter is not counted, which is a good thing.

e.g. The first else{} with the while loop is what you would concentrate on. the other stuff is just for checks.

string t = "11;;22;;"

Since you'll be reading each line of the file into some set string, you should be able to use this example.


----------

