P.Musiał
P.Musiał

Reputation: 81

Passing a file to a few functions

I'm opening a file in a main function. I want to pass this file to a few functions but it looks like a first called function is clearing this file. This is a file:

1 5 6 8
6 5
1
2 6 8
6 7 5 1 2 4

First function counts lines in file. Second function counts the number of individual numbers.

int countTransactions(ifstream &dataBaseFile) {
    int numOfTransactions = 0;
    string line;

    while(getline(dataBaseFile, line))
        numOfTransactions++;

    cout << "countTransaction" << endl;
    cout << numOfTransactions << endl;
    return numOfTransactions;
}

void countItems(ifstream &dataBaseFile) {
    map<int, int> items;
    map<int, int>::iterator it;
    int item;

    while(!dataBaseFile.eof()) {
        dataBaseFile >> item;

        it = items.find(item);
        if(it != items.end()) {
            it->second++;
            continue;
        } else items.insert(make_pair(item, 1));
    }

    for(it = items.begin(); it != items.end(); it++)
        cout << it->first << " => " << it->second << endl;
}

int main() {
    ifstream dataBaseFile("database3.txt", ios::in);

    if(!dataBaseFile.good()) {
        cout << "Failure while opening file";
        exit(1);
    }

    countItems(dataBaseFile);
    countTransactions(dataBaseFile);

    dataBaseFile.close();
}

This is an output:

countTransation
5
countItems

Upvotes: 2

Views: 70

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726509

std::ifstream has a state, meaning that operations that you apply to it influence results of future operations. For example, streams have a reading position. When you read something from a stream, reading position advances by the amount of data you have read.

When you pass dataBaseFile to countItems, it reads the entire file, and advances the reading position all the way to the end. This is where the position remains when you call countTransactions, so it thinks there is nothing to read.

Resetting the read position back to zero will fix this problem:

countItems(dataBaseFile);
dataBaseFile.clear(); // To clear out EOF
dataBaseFile.seekg(0, ios::beg);
countTransactions(dataBaseFile);

However, this is not ideal in terms of performance, because you end up reading the file multiple times. When the file is small, you would be better off reading the entire file into memory, e.g. into std::vector<std::string>, and the using the in-memory representation for much faster access.

Upvotes: 7

Related Questions