0

I'm trying to read info from a txt file but something isnt working out. I need to read each line and save that in a variable that belongs to the class Bilhete.

Alexandre
20/12/2015
1,2,3,4
Luis
30/10/1990
3,4,5,6

This is my txt.

This represents a ticket(bilhete in portuguese): - name of the owner - expirity date - The competitions that I have access to. Each number represents the id of the competition. There is a competition class in my project but I dont think it is very important for this question

void Campeonato::readFileBilhetes(string filename) {


    ifstream ficheiro_leitura(filename.c_str());

    vector<Prova*> vecprovas = calendario->getProvas();
    vector <int> indices; //vector with competitions id

    if(!ficheiro_leitura)
        throw ErroNoFicheiro(filename);
    else{
        string dono, data, provasNoBilhete, vendido; //owner, date, competitions in the ticket, 

        while (!ficheiro_leitura.eof()){

            getline(ficheiro_leitura, dono);
            getline(ficheiro_leitura, data);
            getline(ficheiro_leitura, provasNoBilhete);


            stringstream dataSs;
            date d;
            dataSs << data;
            int dia, mes, ano;  //day, month, //year
            char tmp;
            dataSs >> dia >> tmp >> mes >> tmp >> ano;

            if(dia < 1 || dia > 31|| mes < 1 || mes > 12 || ano < 1 || (dia > 28 && mes == 2) || (dia > 30 && mes == 4) || (dia > 30 && mes == 6) || (dia > 30 && mes == 9) || (dia > 30 && mes == 11)){
                cout << "Data invalida!";
            }
            else{
                d.dia = dia; //day
                d.mes = mes; //month
                d.ano = ano; //year
            }



            string s1 = "";
            string s2= "";



            stringstream provasS;
            int i = 0;
            while (provasNoBilhete[i] != '\n' && provasNoBilhete[i] != '\0'){

                if(provasNoBilhete[i] == ','){
                    int indice;
                    provasS.clear();
                    provasS.str("");
                    provasS.str(s2);
                    provasS >> indice;
                    indices.push_back(indice);





                }
                else
                    provasS << provasNoBilhete[i];


                ++i;
                Bilhete *bi1 = new Bilhete(d, dono, indices);
                inserirBilhete(*bi1); //insert
            }


        }
    }

}

How do I correcly save those values?

Best regards

Perseverance
  • 317
  • 5
  • 16
  • 1
    Can you clarify the problem that you are having? – badfilms Dec 22 '15 at 04:04
  • [You should not use `while(!ifstream.eof()`.](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong), which may be the source of your problem. – Beta Dec 22 '15 at 05:26

2 Answers2

0

I'm not sure exactly what values you are having issues when reading in your file, but here is an example that shows how to read in the values you are trying to obtain. This will correctly read in the name into a string, the date into separate integers, and the competition ids into a vector of integers. I find that using the iss.peek method very helpful for debugging stringstream's. Here you can see I am using this method to ensure that I'm reading in a valid file.

Also, as Beta said, I would recommend not using file.eof(). Try using getline in the conditional of your loop.

fstream infile(file);
string linha, dono;
int dia, mes, ano;
vector<int> campeonatoIds;

while (getline(infile, dono)) // get name and check status file stream
{
    cout << dono << endl;
    // read in date
    getline(infile, linha);
    int tmp;
    istringstream iss (linha);
    iss >> dia;
    if (iss.peek() != '/')
    {
        cerr << "incorrectly formatted file" << endl;
        exit(EXIT_FAILURE);
    }
    iss.ignore();
    iss >> mes;
    if (iss.peek() != '/')
    {
        cerr << "incorrectly formatted file" << endl;
        exit(EXIT_FAILURE);
    }
    iss.ignore();
    iss >> ano;


    cout << dia << "/" << mes << "/" << ano << endl;

    // read in competition ids
    getline(infile, linha);
    istringstream iss2(linha);
    while (iss2.peek() != ',' && iss2.good())
    {
        iss2 >> tmp;
        cout << tmp << ",";
        campeonatoIds.push_back(tmp);
        iss2.ignore();
    }
    cout << endl;
}

However, I personally thing that using getline is easier and cleaner than using a stringstream in this situation. Here is the same code refactored to use getline.

fstream infile(file);
string linha, dono;
int dia, mes, ano;
vector<int> campeonatoIds;

while (getline(infile, dono)) // get name and check status file stream
{
    cout << dono << endl;
    // read in date
    getline(infile, linha);
    istringstream iss (linha);
    string tmpstr1;
    getline(iss, tmpstr1, '/');
    dia = atoi(tmpstr1.c_str());

    getline(iss, tmpstr1, '/');
    mes = atoi(tmpstr1.c_str());

    getline(iss, tmpstr1, '/');
    ano = atoi(tmpstr1.c_str());

    cout << dia << "/" << mes << "/" << ano << endl;

    // read in competition ids
    getline(infile, linha);
    istringstream iss2(linha);
    string tmpstr2;
    while (getline(iss2, tmpstr2, ','))
    {
        campeonatoIds.push_back(atoi(tmpstr2.c_str()));
    }

    for (auto it : campeonatoIds)
    {
        cout << it << ",";    
    }
    cout << endl;
    campeonatoIds.clear();
}

As you can see, I am using getline in the while loop without, which allows you to check the validity of the file. Additionally, I think using getline allows you to provide an optional delimiter for simple separation of file streams.

Brad Frost
  • 126
  • 4
0

I would start by overloading operator>> for the ticket class, so that has the body to read a single ticket. Then I'd read the tickets from the stream using that operator.

The standard already defines a get_tgime (and put_time) manipulator to read a time from a stream into a struct tm, so we might as well use those.

Code might look something like this:

friend std::istream &operator>>(std::istream &is, ticket &t) {
    std::getline(is, t.name);

    is >> std::get_time(&t.date, " %d / %m / %Y ");

    std::string temp;
    std::getline(is, temp);

    t.events = parse_list<int>(temp);
    return is;
}

The parse_list would be something on this general order:

template <class T>
std::vector<T> parse_list(std::string const &in) {
    T temp;
    std::vector<T> ret;

    std::istringstream buf(in);

    while (buf >> temp) {
        ret.push_back(temp);
        buf.ignore(1);
    }
    return ret;
}

With those defined, reading a file full of ticket data and putting it all into a vector would look something like this:

std::vector<ticket> tickets { std::istream_iterator<ticket>(input),
    std::istream_iterator<ticket>() };
Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035