Help with simple file reading issue please

Discussion in 'C++' started by Shane, Aug 23, 2004.

  1. Shane

    Shane Guest

    Hi,

    Thanks in advance for the help. I have been to many websites and tried
    several solutions to my problem, but have fixed part of it. It's time to
    come humbly to the newsgroups for help :)

    By the way, please don't reply just to tell me that my code isn't optimized
    and that I should use a delimited database rather than a line by line
    record. If I had my way, I'd do it differently too.

    I am reading in a file that looks like this..
    <snip>
     
    Shane, Aug 23, 2004
    #1
    1. Advertising

  2. Shane

    Shane Guest


    > Thanks in advance for the help. I have been to many websites and tried
    > several solutions to my problem, but have fixed part of it. It's time to
    > come humbly to the newsgroups for help :)
    >
    > By the way, please don't reply just to tell me that my code isn't

    optimized
    > and that I should use a delimited database rather than a line by line
    > record. If I had my way, I'd do it differently too.
    >
    > I am reading in a file that looks like this..
    > <snip>

    Crap, let's try that again..

    uh, looks like this..

    item2
    type
    dude

    4.44
    avail

    With code that looks like this...

    Multi is an ifstream

    Multi.open("Multimedia.txt");
    if (!Multi){}
    else{
    while (!Multi.eof()){
    m = new Multimedia();
    string Item;
    getline(Multi, Item, '\n');
    m->setName(Item);
    string Type;
    getline(Multi, Type, '\n');
    m->setType(Type);
    string By;
    getline(Multi, By, '\n');
    m->setAuthor(By);
    string Owner;
    getline(Multi, Owner, '\n');
    m->setOwner(Owner);
    float Price;
    Multi >> Price;
    Multi.ignore(100,'\n');
    m->setPrice(Price);
    string Availability;
    getline(Multi, Availability, '\n');
    m->setStatus(Availability);

    MM.push_back(*m); //linked list (STL)
    }
    }
    Multi.close();

    It was worse until I added the Multi.ignore line, but I still have a
    problem.
    My result is two records instead of one. Obviously I am pulling the price
    information out twice (left in buffer?) and it is obvious that it has to do
    with the fact that I am using cin to get it. I can't use getline for
    getting a float, so I need to find a way to clear the buffer out.

    Am I even on the right track? Can someone help me please?

    Shane
     
    Shane, Aug 23, 2004
    #2
    1. Advertising

  3. Shane

    David Hilsee Guest

    "Shane" <> wrote in message
    news:...
    >
    > > Thanks in advance for the help. I have been to many websites and tried
    > > several solutions to my problem, but have fixed part of it. It's time

    to
    > > come humbly to the newsgroups for help :)
    > >
    > > By the way, please don't reply just to tell me that my code isn't

    > optimized
    > > and that I should use a delimited database rather than a line by line
    > > record. If I had my way, I'd do it differently too.
    > >
    > > I am reading in a file that looks like this..
    > > <snip>

    > Crap, let's try that again..
    >
    > uh, looks like this..
    >
    > item2
    > type
    > dude
    >
    > 4.44
    > avail
    >
    > With code that looks like this...
    >
    > Multi is an ifstream
    >
    > Multi.open("Multimedia.txt");
    > if (!Multi){}
    > else{
    > while (!Multi.eof()){
    > m = new Multimedia();
    > string Item;
    > getline(Multi, Item, '\n');
    > m->setName(Item);
    > string Type;
    > getline(Multi, Type, '\n');
    > m->setType(Type);
    > string By;
    > getline(Multi, By, '\n');
    > m->setAuthor(By);
    > string Owner;
    > getline(Multi, Owner, '\n');
    > m->setOwner(Owner);
    > float Price;
    > Multi >> Price;
    > Multi.ignore(100,'\n');
    > m->setPrice(Price);
    > string Availability;
    > getline(Multi, Availability, '\n');
    > m->setStatus(Availability);
    >
    > MM.push_back(*m); //linked list (STL)
    > }
    > }
    > Multi.close();
    >
    > It was worse until I added the Multi.ignore line, but I still have a
    > problem.
    > My result is two records instead of one. Obviously I am pulling the price
    > information out twice (left in buffer?) and it is obvious that it has to

    do
    > with the fact that I am using cin to get it. I can't use getline for
    > getting a float, so I need to find a way to clear the buffer out.
    >
    > Am I even on the right track? Can someone help me please?


    That looks like the old "improper use of eof" problem. See the FAQ
    (http://www.parashift.com/c -faq-lite/), section 15 ("Input/output via
    <iostream> and <cstdio>"), question 5 ("Why does my input seem to process
    past the end of file?").

    By the way, the dynamic allocation of the Multimedia object (m = new
    Multimedia();) looks like it is unnecessary and possibly causing a memory
    leak. Did you mean to write "Multimedia m;"?

    --
    David Hilsee
     
    David Hilsee, Aug 23, 2004
    #3
  4. Shane

    Shane Guest

    "David Hilsee" <> wrote in message
    news:...
    > "Shane" <> wrote in message
    > news:...
    > >


    <snip>

    > That looks like the old "improper use of eof" problem. See the FAQ
    > (http://www.parashift.com/c -faq-lite/), section 15 ("Input/output via
    > <iostream> and <cstdio>"), question 5 ("Why does my input seem to process
    > past the end of file?").
    >
    > By the way, the dynamic allocation of the Multimedia object (m = new
    > Multimedia();) looks like it is unnecessary and possibly causing a memory
    > leak. Did you mean to write "Multimedia m;"?
    >
    > --
    > David Hilsee
    >
    >


    I looked at that exact article before, but ignored it because it skips the
    whole purpose of using getline for everything else. In other words, if my
    record looks like this:

    Item name with spaces
    Record
    Full Name with spaces

    4.44
    Available on request with spaces

    then I have issues. So I tried your suggestion, but I lose the first cin in
    the record to the x variable. This throws the whole record off. If I use
    getline, I can grab everything in the line and pull it into the variable of
    my choice. Am I missing something?

    Thanks again for the help!
    Shane
     
    Shane, Aug 23, 2004
    #4
  5. Shane

    David Hilsee Guest

    "Shane" <> wrote in message
    news:...
    >
    > "David Hilsee" <> wrote in message
    > news:...
    > > "Shane" <> wrote in message
    > > news:...
    > > >

    >
    > <snip>
    >
    > > That looks like the old "improper use of eof" problem. See the FAQ
    > > (http://www.parashift.com/c -faq-lite/), section 15 ("Input/output via
    > > <iostream> and <cstdio>"), question 5 ("Why does my input seem to

    process
    > > past the end of file?").
    > >
    > > By the way, the dynamic allocation of the Multimedia object (m = new
    > > Multimedia();) looks like it is unnecessary and possibly causing a

    memory
    > > leak. Did you mean to write "Multimedia m;"?
    > >
    > > --
    > > David Hilsee
    > >
    > >

    >
    > I looked at that exact article before, but ignored it because it skips the
    > whole purpose of using getline for everything else. In other words, if my
    > record looks like this:
    >
    > Item name with spaces
    > Record
    > Full Name with spaces
    >
    > 4.44
    > Available on request with spaces
    >
    > then I have issues. So I tried your suggestion, but I lose the first cin

    in
    > the record to the x variable. This throws the whole record off. If I use
    > getline, I can grab everything in the line and pull it into the variable

    of
    > my choice. Am I missing something?
    >
    > Thanks again for the help!


    Yes, the example uses operator>>, but the idea can be applied to many other
    circumstances as well. The problem is the same: eof() is being set after
    you attempt to read past the end of the file. The first iteration does not
    attempt to read _past_ the end of the file, so the loop continues on for
    another iteration, adding a second object to the linked list. You do not
    check to see if any of the input operations succeed, so the second iteration
    silently fails to retrieve input from the file after the first iteration
    read all of the input.

    Now, suppose there were a function std::istream& operator>>(std::istream&,
    Multimedia&) that would allow you to read a Multimedia from a stream. Then
    you could write your loop as

    Multimedia m;
    while( Multi >> m ) {
    MM.push_back(m);
    }

    if ( !Multi.eof() ) {
    // Something bad happened. Should have attempted to read past
    // the end of the file to end the loop.
    }

    The above would silently ignore a partial Multimedia entry, but you could
    fix that, if you like. The other option would be to add error handling to
    your code. For example,

    getline(Multi, Item, '\n');

    should be changed so you know if the read was successful, like so

    if ( !getline(Multi, Item, '\n') ) {
    std::cerr << "Error reading Item" << std::endl;
    break;
    }

    You'll need to add similar error handling for the other input operations you
    perform. Your code will now complain loudly when it fails to read from the
    file. However, that would still render your call to eof() useless, because
    the loop will most likely end once an error has occurred, not when eof()
    returns true. Give those changes a shot and see if it helps you understand
    what's going on.

    --
    David Hilsee
     
    David Hilsee, Aug 23, 2004
    #5
  6. Shane

    Jack Klein Guest

    On Sun, 22 Aug 2004 19:16:31 -0700, "Shane"
    <> wrote in comp.lang.c++:

    >
    > "David Hilsee" <> wrote in message
    > news:...
    > > "Shane" <> wrote in message
    > > news:...
    > > >

    >
    > <snip>
    >
    > > That looks like the old "improper use of eof" problem. See the FAQ
    > > (http://www.parashift.com/c -faq-lite/), section 15 ("Input/output via
    > > <iostream> and <cstdio>"), question 5 ("Why does my input seem to process
    > > past the end of file?").
    > >
    > > By the way, the dynamic allocation of the Multimedia object (m = new
    > > Multimedia();) looks like it is unnecessary and possibly causing a memory
    > > leak. Did you mean to write "Multimedia m;"?
    > >
    > > --
    > > David Hilsee
    > >
    > >

    >
    > I looked at that exact article before, but ignored it because it skips the
    > whole purpose of using getline for everything else. In other words, if my
    > record looks like this:
    >
    > Item name with spaces
    > Record
    > Full Name with spaces
    >
    > 4.44
    > Available on request with spaces
    >
    > then I have issues. So I tried your suggestion, but I lose the first cin in
    > the record to the x variable. This throws the whole record off. If I use
    > getline, I can grab everything in the line and pull it into the variable of
    > my choice. Am I missing something?
    >
    > Thanks again for the help!
    > Shane


    Yes, you are missing the fact that in C++ and C, from which C++
    inherits the behavior, end of file does not work the way you think.
    Not for C style <stdio.h> streams nor for C++ stream objects.

    The end of file indicator is NEVER set for a stream because you just
    read the last item from the stream and the NEXT read will fail. The
    end of file indicator is only set for a stream AFTER you try to read
    PAST THE END of the file.

    You are checking for end of file before you do the read. If there is
    one item in a file and you have read that one item, the end of file
    indicator will be false. When you try to read the second item, there
    is nothing left in the file and the read fails, sets the end of file
    indicator, and leaves the destination untouched. So it still contains
    whatever was previously in it, perhaps the first record.

    You need to do the check for end of file either after reading, or
    while reading the data.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Aug 23, 2004
    #6
  7. Shane

    Daniel T. Guest

    In article <>,
    "Shane" <> wrote:

    > > Thanks in advance for the help. I have been to many websites and tried
    > > several solutions to my problem, but have fixed part of it. It's time to
    > > come humbly to the newsgroups for help :)
    > >
    > > By the way, please don't reply just to tell me that my code isn't

    > optimized
    > > and that I should use a delimited database rather than a line by line
    > > record. If I had my way, I'd do it differently too.
    > >
    > > I am reading in a file that looks like this..
    > > <snip>

    > Crap, let's try that again..
    >
    > uh, looks like this..
    >
    > item2
    > type
    > dude
    >
    > 4.44
    > avail
    >
    > With code that looks like this...
    >
    > Multi is an ifstream
    >
    > Multi.open("Multimedia.txt");
    > if (!Multi){}
    > else{
    > while (!Multi.eof()){
    > m = new Multimedia();
    > string Item;
    > getline(Multi, Item, '\n');
    > m->setName(Item);
    > string Type;
    > getline(Multi, Type, '\n');
    > m->setType(Type);
    > string By;
    > getline(Multi, By, '\n');
    > m->setAuthor(By);
    > string Owner;
    > getline(Multi, Owner, '\n');
    > m->setOwner(Owner);
    > float Price;
    > Multi >> Price;
    > Multi.ignore(100,'\n');
    > m->setPrice(Price);
    > string Availability;
    > getline(Multi, Availability, '\n');
    > m->setStatus(Availability);
    >
    > MM.push_back(*m); //linked list (STL)
    > }
    > }
    > Multi.close();
    >
    > It was worse until I added the Multi.ignore line, but I still have a
    > problem.
    > My result is two records instead of one. Obviously I am pulling the price
    > information out twice (left in buffer?) and it is obvious that it has to do
    > with the fact that I am using cin to get it. I can't use getline for
    > getting a float, so I need to find a way to clear the buffer out.
    >
    > Am I even on the right track? Can someone help me please?


    Try this:

    istream& operator>>( istream& s, Multimedia& m )
    {
    string item;
    getline( s, item );
    m.setName( item );
    getline( s, item );
    m.setType( item );
    // etc...
    return s;
    }

    Then in your code:

    Multimedia m;
    while ( Multi >> m )
    MM.push_back( m );
     
    Daniel T., Aug 23, 2004
    #7
  8. Shane

    Shane Guest

    >
    > Yes, the example uses operator>>, but the idea can be applied to many

    other
    > circumstances as well. The problem is the same: eof() is being set after
    > you attempt to read past the end of the file. The first iteration does

    not
    > attempt to read _past_ the end of the file, so the loop continues on for
    > another iteration, adding a second object to the linked list. You do not
    > check to see if any of the input operations succeed, so the second

    iteration
    > silently fails to retrieve input from the file after the first iteration
    > read all of the input.
    >
    > Now, suppose there were a function std::istream& operator>>(std::istream&,
    > Multimedia&) that would allow you to read a Multimedia from a stream.

    Then
    > you could write your loop as
    >
    > Multimedia m;
    > while( Multi >> m ) {
    > MM.push_back(m);
    > }
    >
    > if ( !Multi.eof() ) {
    > // Something bad happened. Should have attempted to read past
    > // the end of the file to end the loop.
    > }
    >
    > The above would silently ignore a partial Multimedia entry, but you could
    > fix that, if you like. The other option would be to add error handling to
    > your code. For example,
    >
    > getline(Multi, Item, '\n');
    >
    > should be changed so you know if the read was successful, like so
    >
    > if ( !getline(Multi, Item, '\n') ) {
    > std::cerr << "Error reading Item" << std::endl;
    > break;
    > }
    >
    > You'll need to add similar error handling for the other input operations

    you
    > perform. Your code will now complain loudly when it fails to read from

    the
    > file. However, that would still render your call to eof() useless,

    because
    > the loop will most likely end once an error has occurred, not when eof()
    > returns true. Give those changes a shot and see if it helps you

    understand
    > what's going on.
    >
    > --
    > David Hilsee
    >
    >


    Thanks for all the suggestions. It's working properly now :)

    Shane
     
    Shane, Aug 23, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    552
    Chris Uppal
    May 5, 2005
  2. KK
    Replies:
    2
    Views:
    664
    Big Brian
    Oct 14, 2003
  3. MuZZy
    Replies:
    7
    Views:
    1,801
    Mike Hewson
    Jan 7, 2005
  4. Replies:
    14
    Views:
    552
    Karl Heinz Buchegger
    Nov 2, 2005
  5. W.Sh
    Replies:
    5
    Views:
    129
    Luke Matuszewski
    Feb 11, 2006
Loading...

Share This Page