Thread: Reading from file stream using ifstream object and storing in a map

  1. #1
    Registered User ex-mortis's Avatar
    Join Date
    Mar 2012
    Posts
    37

    Reading from file stream using ifstream object and storing in a map

    Code:
    void loadGames(){
        std::ifstream load("Gamelist.gl");
        num_holder;
        title_holder;
        hours_holder;
        load.getline(num_holder, 1, ' ');
        load.getline(title_holder, 20, ' ');
        load.getline(hours_holder, 5);
        Games[num_holder].title = title_holder;
        Games[num_holder].hoursPlayed = hours_holder;
    }
    I'm having some trouble getting this to work. At first I tried to read directly into an int, std::string and double with no luck so I tried reading into character arrays and converting them to ints and std::strings with even less luck. I think this is probably not a good way to go about this and there has to be a more efficient way. Can someone help please?

    P.S. Posting the complete code is unnecessary but here is the definition of the std::map container I'm placing the values in just in case:

    Code:
    struct Game{
        std::string title;
        double hoursPlayed;
    
    };
    
    typedef std::map<int, Game> gameMap;
    gameMap Games;
    Last edited by ex-mortis; 07-24-2012 at 10:39 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    What are these statements?
    Code:
    num_holder;
    title_holder;
    hours_holder;
    Based on subsequent code, it looks like they are variables, but you didn't show their declarations, plus writing them like this results in code that has no net effect. You could very well have written:
    Code:
    ;
    ;
    ;
    Did you perhaps intend to declare (and hence define) the variables instead?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    What does the file itself look like?

    istream::getline - C++ Reference
    Code:
        num_holder;
        title_holder;
        hours_holder;
        load.getline(num_holder, 1, ' ');
        load.getline(title_holder, 20, ' ');
        load.getline(hours_holder, 5);
    What exactly are the first 3 lines doing?
    Are they declaring char arrays of a suitable size, or is this just down to your creative editing?

    Passing 1 to getline() makes no sense, as it stores (n-1) (ie, ZERO) characters.

    The problem with incremental parsing happens when the file is malformed, and you lose sync with what is in the file compared to what you expect.
    Say for example someone tries to enter a 25 character title_holder. The excess characters will get stored in hours_holder.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User ex-mortis's Avatar
    Join Date
    Mar 2012
    Posts
    37
    Quote Originally Posted by laserlight View Post
    What are these statements?
    Code:
    num_holder;
    title_holder;
    hours_holder;
    Based on subsequent code, it looks like they are variables, but you didn't show their declarations, plus writing them like this results in code that has no net effect. You could very well have written:
    Code:
    ;
    ;
    ;
    Did you perhaps intend to declare (and hence define) the variables instead?
    Like I said, I am not sure what types of variables to declare because I haven't found a method that works yet and so I omitted the declarations.


    Quote Originally Posted by Salem View Post
    What does the file itself look like?

    istream::getline - C++ Reference
    Code:
        num_holder;
        title_holder;
        hours_holder;
        load.getline(num_holder, 1, ' ');
        load.getline(title_holder, 20, ' ');
        load.getline(hours_holder, 5);
    What exactly are the first 3 lines doing?
    Are they declaring char arrays of a suitable size, or is this just down to your creative editing?

    Passing 1 to getline() makes no sense, as it stores (n-1) (ie, ZERO) characters.

    The problem with incremental parsing happens when the file is malformed, and you lose sync with what is in the file compared to what you expect.
    Say for example someone tries to enter a 25 character title_holder. The excess characters will get stored in hours_holder.
    Right now this code is completely meaningless and is only a general outline of what I want to do. I realize it doesn't work. Basically this is a simple program that stores the titles and number of hours played of videogames in the order they were added in a map. I have a function called saveGames that looks like this:

    Code:
    void saveGames(){
        std::ofstream save("Gamelist.gl");
        for(std::map<int, Game>::iterator ii=Games.begin(); ii!=Games.end(); ++ii){
            save << ii->first << " " << ii->second.title << " " << ii->second.hoursPlayed << std::endl;
        }
        save.close();
    }
    And the contents of Gamelist.gl are in this format: <number><whitespace><title (I have a function that replaces whitespaces with underscores)><whitespace><hours>. I want to read data with whitespaces as the delimiting character and store them in variables that I then assign to my map.

    I'm not exactly sure how to do that so I am really just asking what the best way to go about that is, not how to make the current code compile.

    P.S. That's weird. Not like anyone would try to enter a 25 character title (maybe a miscalculation, I will probably raise the max amount). Do you by any chance know how to avoid that or do you know a safer and more reliable way?

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Like I said, I am not sure what types of variables to declare because I haven't found a method that works yet and so I omitted the declarations.
    No. You did not say that. You said you had tried a couple of different things. It is natural for us to assume that what you posted is what you have written.

    This forum has some awesome skill in the form of its community, but we can't read minds.

    Please show us exactly what you are trying to do exactly as you are trying to do it or we can only speculate about what is going wrong.

    Soma

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    If you're pretty sure that space is a good delimiter in your file when you generate it, then perhaps something like this.
    Code:
    #include<iostream>
    #include<fstream>
    #include<string>
    #include<sstream>
    using namespace std;
    int main()
    {
        string line;
        string one, two, three;
        ifstream load("Gamelist.gl");
        while ( getline(load,line) ) {
            istringstream is(line);
            if ( is >> one >> two >> three ) {
                cout << one << "," << two << "," << three << endl;
            }
        }
    }
    Everything is a std::string, so no messy char arrays where you have to guess the length is "good enough".

    Results
    Code:
    $ cat Gamelist.gl 
    1 hello world
    2 this_is_a_very_long_string and_this_is_pretty_long_as_well
    $ ./a.out 
    1,hello,world
    2,this_is_a_very_long_string,and_this_is_pretty_long_as_well
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User ex-mortis's Avatar
    Join Date
    Mar 2012
    Posts
    37
    Quote Originally Posted by phantomotap View Post
    No. You did not say that. You said you had tried a couple of different things. It is natural for us to assume that what you posted is what you have written.

    This forum has some awesome skill in the form of its community, but we can't read minds.

    Please show us exactly what you are trying to do exactly as you are trying to do it or we can only speculate about what is going wrong.

    Soma
    Well, I'm sorry. "At first I tried to read directly into an int, std::string and double with no luck so I tried reading into character arrays and converting them to ints and std::strings with even less luck. I think this is probably not a good way to go about this and there has to be a more efficient way." seemed pretty straightforward to me. But I did say I don't have a clue how to go about it so I cannot show you exactly how I am trying to do it. I only included the code as a substitute for a long and potentially confusing explanation.

    EDIT:

    Quote Originally Posted by Salem View Post
    if ( is >> one >> two >> three ) {
    cout << one << "," << two << "," << three << endl;
    }
    [/code]
    My best guess is that this places the contents of is into one up until the first whitespace, two up until the next, and then three up until the next (end of file). Is that correct? If so, I think that would work perfectly.

    EDIT: Actually I overlooked something, since variables one and three need to be int and double respectively. Is there something similar to istringstream that applies to numbers?
    Last edited by ex-mortis; 07-24-2012 at 11:47 AM.

  8. #8
    Registered User ex-mortis's Avatar
    Join Date
    Mar 2012
    Posts
    37
    Got it work just in case somebody else out there has a similar problem. This is the final loadGames() function:

    Code:
    void loadGames(){
        std::string line, num_holder, title_holder, hours_holder;
        std::ifstream load("Gamelist.gl");
        long int num;
        double hours;
        while (getline(load, line)) {
            std::istringstream iss(line);
            if ( iss >> num_holder >> title_holder >> hours_holder ) {
                num = strtol(num_holder.c_str(), NULL, 0);
                hours = strtod(hours_holder.c_str(), NULL);
            }
            std::replace(title_holder.begin(), title_holder.end(), '_', ' ');
            Games[num].title = std::string(title_holder);
            Games[num].hoursPlayed = hours;
        }
    }
    It works beautifully.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Why are you casting to std::string when it already is a std::string?
    Games[num].title = std::string(title_holder);
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Actually it is a constructor call, the copy constructor to be specific.

  11. #11
    Registered User ex-mortis's Avatar
    Join Date
    Mar 2012
    Posts
    37
    Quote Originally Posted by Elysia View Post
    Why are you casting to std::string when it already is a std::string?
    Games[num].title = std::string(title_holder);
    Nice spot. It's a little carry-over from my char array design that I forgot to fix actually. Although what it does at the moment isn't catastrophic having a copy is pretty much unnecessary. Thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Segfault in reading file stream
    By brobot in forum C Programming
    Replies: 5
    Last Post: 12-19-2011, 02:55 PM
  2. Problem reading from file stream
    By shmitson in forum C Programming
    Replies: 0
    Last Post: 04-05-2011, 04:37 PM
  3. Help - Reading a file and storing it as a 2d Array.
    By MetallicaX in forum C Programming
    Replies: 2
    Last Post: 03-08-2009, 07:33 PM
  4. reading file and storing to arrays
    By dayknight in forum C Programming
    Replies: 4
    Last Post: 04-27-2006, 05:17 AM
  5. File Reading and storing to 1 variable
    By Rare177 in forum C Programming
    Replies: 34
    Last Post: 07-13-2004, 12:58 PM