ifstream::getline() synatx

Discussion in 'C++' started by Mark S., Apr 17, 2009.

  1. Mark S.

    Mark S. Guest

    Hi,
    since my next exercise involves working with files, I tried to learn
    some more about ifstream. So far in the book, reading from files was
    generally handled like this:
    ifstream in(file); // (1)
    string s;
    while(getline(in, s)) // (2)
    ...

    So far, so good. But when looking around, I also found the following syntax:
    ifstream in; // (3)
    string s;
    in.open(file); // (4)
    in.getline(s, 30); // (5)
    ...
    in.close(); // (6)

    Both works, of course. The second way of handling files made more sense
    to me, but I was still wondering about the syntax. Google brought up
    this page:
    http://www.cplusplus.com/reference/iostream/ifstream/

    Now my questions:

    a) On the web page, it says: "The file to be associated with the stream
    can be specified either as a parameter in the constructor or by calling
    member open."
    Now, the way I understand it is this: (1) is opening the file via the
    constructor (and creates the object "in"?) and (3) is creating the
    object first, then opening the file explicitly (4) and eventually
    closing it (6).
    In the documentation, I don't read anything about a destructor, so I wonder:
    - Why don't I need to close the file in the first example?

    b) My second (more important) question has to do with getline. With (2),
    the _complete_ (!) line is automatically read into the string "line"
    while the second syntax seems to always require a second argument - the
    length that is to be read. This is they way I also interpret the
    documentation, however, the first example clearly works. So..

    - I thought both example used the same functions, just with different
    syntax?
    - How come that the documentation does not mention how to read the
    complete line? Is that part missing? Shouldn't in.getline(s) work the
    same way getline(in, s) does?

    The documentation says that getline() exists in fstream and in string,
    could that be the problem? If so, how do I resolve it (I mean, isn't it
    pretty common to have strings when you are working with files?)?

    -> Basically, which way should I use to handle files? Or am I
    overlooking something?

    Thank you for your time!

    Kind regards
    Mark
     
    Mark S., Apr 17, 2009
    #1
    1. Advertising

  2. Mark S.

    Mark S. Guest

    Obnoxious User wrote:
    > On Fri, 17 Apr 2009 19:14:42 +0200, Mark S. wrote:
    >
    >> Hi,
    >> since my next exercise involves working with files, I tried to learn
    >> some more about ifstream. So far in the book, reading from files was
    >> generally handled like this:
    >> ifstream in(file); // (1)
    >> string s;
    >> while(getline(in, s)) // (2)
    >> ...
    >>
    >> So far, so good. But when looking around, I also found the following
    >> syntax:
    >> ifstream in; // (3)
    >> string s;
    >> in.open(file); // (4)
    >> in.getline(s, 30); // (5)

    >
    > istream& istream::getline (char* s, streamsize n )
    >
    > You can't pass a std::string as an argument for 's'. It won't compile.
    > You need to allocate a buffer.
    >
    > char buffer[20];
    > in.getline(buffer,20);

    I see.

    >> ...
    >> in.close(); // (6)
    >>
    >> Both works, of course.

    >
    > No they don't.

    Ups, I compiled the second example without the actual getline. *blush*
    All of this makes a lot more sense now!

    > The destructor of fstream will close the file if you haven't
    > done so yourself.

    Yes, but what if I want to close it beforehand? Then I just in.close,
    right? Also, I thought it is "good programming" to make sure these kind
    of things are done right? So I guess my question should not only have
    been whether or not it closes, but also if I should close in manually.

    >> b) My second (more important) question has to do with getline. With (2),
    >> the _complete_ (!) line is automatically read into the string "line"

    >
    > That's because std::getline() is an auxiliary function to make it easier
    > to read a text line from any input stream without having to worry about
    > buffer sizes.
    >
    >> while the second syntax seems to always require a second argument - the
    >> length that is to be read. This is they way I also interpret the
    >> documentation, however, the first example clearly works. So..

    >
    > istream& istream::getline (char* s, streamsize n )
    >
    > This member function needs to know how much it can store in the buffer
    > pointed to by 's'. That's why you need to supply the size.
    >
    >> - I thought both example used the same functions, just with different
    >> syntax?

    >
    > No, they use different functions.

    Sorry again if this is a stupid question - but how do I make sure which
    one is used? From my newbie perspective, both do the same (read a line
    from a file). Moreover, how do I know which one is the better choice for
    the task at hand?
     
    Mark S., Apr 18, 2009
    #2
    1. Advertising

  3. Mark S.

    James Kanze Guest

    On Apr 18, 8:24 am, "Mark S." <> wrote:
    > Obnoxious User wrote:
    > > On Fri, 17 Apr 2009 19:14:42 +0200, Mark S. wrote:


    [...]
    > > The destructor of fstream will close the file if you haven't
    > > done so yourself.


    > Yes, but what if I want to close it beforehand? Then I just
    > in.close, right? Also, I thought it is "good programming" to
    > make sure these kind of things are done right? So I guess my
    > question should not only have been whether or not it closes,
    > but also if I should close in manually.


    It depends. In principal, close can fail, so should not be left
    to the destructor. In practice, when inputting, you're checking
    the status after each input anyway; if close fails, there's
    something seriously wrong with the system, and you can't do much
    about it, so there's really no strong motivation for not just
    leaving it to the destructor. For output, close() can fail even
    though all earlier output succeeded, and in such cases, your
    data may not be correctly written. At the very least, you have
    to inform the user of this in some way---if you're writing to a
    file, you may even want to delete the file, rather than leaving
    corrupt data lying around. So an explicit close in the normal
    program flow is essential. On the other hand, if some other
    serious error occured, so that you're abandonning processing
    anyway (and will report an error and maybe delete the file
    anyway), then it probably doesn't matter if the data in the file
    isn't valid, so you can allow the close in the destructor to do
    the job. (In this case, the destructor would typically be
    called as a result of stack unwinding from an exception.)

    [...]
    > >> while the second syntax seems to always require a second argument - the
    > >> length that is to be read. This is they way I also interpret the
    > >> documentation, however, the first example clearly works. So..


    > > istream& istream::getline (char* s, streamsize n )


    > > This member function needs to know how much it can store in the buffer
    > > pointed to by 's'. That's why you need to supply the size.


    > >> - I thought both example used the same functions, just with different
    > >> syntax?


    > > No, they use different functions.


    > Sorry again if this is a stupid question - but how do I make
    > sure which one is used? From my newbie perspective, both do
    > the same (read a line from a file). Moreover, how do I know
    > which one is the better choice for the task at hand?


    One's a member function, the other isn't, so the calling syntax
    is different. And they take different types of arguments.

    As to which is better, IMHO, there's never any valid reason to
    input into a char[]. The member function is probably present
    mainly for historical reasons---it was around before std::string
    was invented.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 18, 2009
    #3
  4. Mark S.

    Mark S. Guest

    more questions...

    Arghhh, this whole exercise is more and more difficult for me. I'm at a
    total loss here. This is the exercise (TICPP, 7.1):
    Create a Text class that contains a string object to hold the text of a
    file. Give it two constructors: a default constructor and a constructor
    that takes a string argument that is the name of the file to open. When
    the second constructor is used, open the file and read the contents into
    the string member object. Add a member function contents( ) to return
    the string so (for example) it can be printed. In main( ), open a file
    using Text and print the contents.

    For testing purposes, I tried to implement the procedure in main() first.

    Before I wrote:
    > ifstream in(file);


    At that point I assumed I could easily define "file" like this:
    string file = "E01.cpp";

    But of course the argument needs to be a const char* (I still don't
    really know what the difference between string and char* is - many
    websites seem to use both terms simultaneously), so I need to convert it
    first. Google brought up this (
    http://www.codeguru.com/cpp/cpp/string/general/article.php/c13267 ):
    char* name = new char[strlen("marius")+1];
    strcpy(name, "marius");

    but I can't get it to work. I guess the "+1" is for the terminating \0,
    but strlen is problematic anyways, which is, I THINK, from cstring (?).
    So I modified it:
    string a = "E01.cpp";
    char* b = new char[(a.length())+1];
    But then I don't know how to copy the string!

    The reference:
    http://www.cplusplus.com/reference/string/string/copy/

    says
    size_t copy ( char* s, size_t n, size_t pos = 0) const;

    Except the words "copy", "char* s" and "const", I have no idea what the
    words mean and I don't understand the whole syntax of the line. Only
    with the help of their description below, their example and Google I was
    able to figure out some parts (but I still don't know why there is a
    "const" at the end or why they use size_t instead of the unsigned int,
    which it says it is). But seriously, how does one read this line??? How
    do I go from not knowing anything about this function to writing a
    working line of code? Is there a tutorial on how to read these things?

    Anyways, in their example
    size_t length;
    char buffer[20];
    string str ("Test string...");
    length=str.copy(buffer,6,5);
    buffer[length]='\0';
    cout << "buffer contains: " << buffer << "\n";

    the string is copied to the char array (which I guess is the same as
    char* , right?) , but only 6 characters starting at position 5. Since
    all parameters are required, *I don't see how just to copy a complete
    string*, without defining the length first. I would have something like
    this in mind:
    string a = "can be very long or short, whatever";
    char copyhere[] = a.length(); // or a.length + 1 ?
    copyhere = a; || a.copy(copyhere); || copyhere = copy(a);
    Or something like that. But nothing works and I am quite frustrated
    right now so I would really appreciate any help you guys could give me.

    Thank you in advance!

    Kind regards
    Mark
     
    Mark S., Apr 18, 2009
    #4
  5. Mark S.

    Phlip Guest

    Re: more questions...

    Obnoxious User wrote:

    > 'char *'-strings are old school C strings. Avoid them if you're learning.
    > Use only std::string. It's a complete design failure that the fstream
    > classes don't accept std::string.


    You really think the Committee didn't think of that? They set a precedent
    against silent type promotions that cause more trouble than they are worth
    at scaling time. Just type the freaking .c_str() yourself.
     
    Phlip, Apr 18, 2009
    #5
  6. Mark S.

    James Kanze Guest

    Re: more questions...

    On Apr 18, 6:14 pm, "Phlip" <> wrote:
    > Obnoxious User wrote:
    > > 'char *'-strings are old school C strings. Avoid them if
    > > you're learning. Use only std::string. It's a complete
    > > design failure that the fstream classes don't accept
    > > std::string.


    > You really think the Committee didn't think of that? They set
    > a precedent against silent type promotions that cause more
    > trouble than they are worth at scaling time. Just type the
    > freaking .c_str() yourself.


    He wasn't asking for an implicit conversion of std::string to
    char const*. I think everyone pretty much understands why that
    would be a bad thing. What surprised him is that
    std::ifstream::eek:pen doesn't take a string as its argument. And
    the reason is purely historical, and related to deadlines when
    producing the last standard---the next version of the standard
    has such an overload.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 18, 2009
    #6
  7. Mark S.

    Phlip Guest

    Re: more questions...

    James Kanze wrote:

    > He wasn't asking for an implicit conversion of std::string to char const*.


    I didn't say he did. I wouldn't have overloaded open() myself, but the
    Committee is certainly free too!
     
    Phlip, Apr 18, 2009
    #7
  8. Mark S.

    Mark S. Guest

    Re: more questions...

    Obnoxious User wrote:
    > 'char *'-strings are old school C strings. Avoid them if you're learning.
    > Use only std::string. It's a complete design failure that the fstream
    > classes don't accept std::string.

    Just to make sure: You mean that I should use c_str() whenever possible?
    I am still confused when "some text" is treated as a string and when as
    a char*. But I guess I'll figure it out eventually as time goes on.

    > You don't need to. You can ask the std::string object to return
    > a temporary c-string when necessary.
    >
    > string s = "E01.cpp";
    > ifstream in(s.c_str());
    > if(in.good()) {
    > while(getline(in,s)) {
    > cout << s << endl;
    > }
    > }

    Thank you, that worked. On to exercise 2! :p

    I must say I do not quite understand the discussion that follows after
    your post. Are you guys saying that C++ is still a work in progress?
     
    Mark S., Apr 19, 2009
    #8
  9. Mark S.

    Mark S. Guest

    James Kanze wrote:
    > On Apr 18, 8:24 am, "Mark S." <> wrote:
    >> Obnoxious User wrote:
    >>> On Fri, 17 Apr 2009 19:14:42 +0200, Mark S. wrote:

    >
    > [...]
    >>> The destructor of fstream will close the file if you haven't
    >>> done so yourself.

    >
    >> Yes, but what if I want to close it beforehand? Then I just
    >> in.close, right? Also, I thought it is "good programming" to
    >> make sure these kind of things are done right? So I guess my
    >> question should not only have been whether or not it closes,
    >> but also if I should close in manually.

    >
    > It depends. In principal, close can fail, so should not be left
    > to the destructor. In practice, when inputting, you're checking
    > the status after each input anyway; if close fails, there's
    > something seriously wrong with the system, and you can't do much
    > about it, so there's really no strong motivation for not just
    > leaving it to the destructor. For output, close() can fail even
    > though all earlier output succeeded, and in such cases, your
    > data may not be correctly written. At the very least, you have
    > to inform the user of this in some way---if you're writing to a
    > file, you may even want to delete the file, rather than leaving
    > corrupt data lying around. So an explicit close in the normal
    > program flow is essential.

    Thanks, this is what I thought.

    > On the other hand, if some other
    > serious error occured, so that you're abandonning processing
    > anyway (and will report an error and maybe delete the file
    > anyway), then it probably doesn't matter if the data in the file
    > isn't valid, so you can allow the close in the destructor to do
    > the job. (In this case, the destructor would typically be
    > called as a result of stack unwinding from an exception.)

    Hmm, but I guess it would still be nice to tell the user what is going
    on. Of course it all depends on the situation, but I think I will try to
    explicitly close files for now.
     
    Mark S., Apr 19, 2009
    #9
  10. Mark S.

    Mark S. Guest

    Re: more questions...

    Obnoxious User wrote:
    > On Sun, 19 Apr 2009 08:10:51 +0200, Mark S. wrote:
    >
    >> Obnoxious User wrote:
    >>> 'char *'-strings are old school C strings. Avoid them if you're
    >>> learning. Use only std::string. It's a complete design failure that the
    >>> fstream classes don't accept std::string.

    >> Just to make sure: You mean that I should use c_str() whenever possible?
    >> I am still confused when "some text" is treated as a string and when as
    >> a char*. But I guess I'll figure it out eventually as time goes on.

    >
    > Any text string in double quotes is of type 'char const *'.
    > "text"

    So when I have
    string str = "some text";
    there is actually some kind of cast happening?

    > C++ is standardized. But the next standard is in the pipeline.

    I see. Thank you.
     
    Mark S., Apr 19, 2009
    #10
  11. Mark S.

    Mark S. Guest

    some more file problems

    Hmm, I still have some trouble with files:

    #include <fstream>
    #include <iostream>
    using namespace std;

    int main()
    {
    string s;
    ifstream in("E07.cpp");
    getline(in, s);
    cout << s << endl;
    in.seekg(0,ios::beg); // (1) going back to beginning of file
    getline(in, s); // works!
    cout << s << endl;
    in.close();

    int i = 0, j = 0;
    ifstream in2("E07.cpp");
    while(getline(in2, s))
    i++;
    in2.seekg(0,ios::beg); // (2) does not work
    while(getline(in2, s))
    j++;
    cout << j << endl; // j is still 0!

    }

    - Why does (1) work, but (2) doesn't??? More importantly, how do I get
    it to work without opening the file a second time?

    - But in case I do want to open a file, how can I open the same file
    with the same identifier?
    ifstream in("test.cpp");
    in.close; // works
    in.open // does not work
    ifstream in("test.cpp"); // also doesn't work of course (double
    declaration of "in")
     
    Mark S., Apr 19, 2009
    #11
  12. Mark S.

    Mark S. Guest

    Re: more questions...

    Obnoxious User wrote:
    >> So when I have
    >> string str = "some text";
    >> there is actually some kind of cast happening?

    >
    > No. In this assignment[1] 'str' will copy the c-string. std::string works
    > with c-strings transparently. Thats why you don't have to bother with
    > the lower levels of string management, std::string will do all that for
    > you. For example, you can't concatenate two c-strings the natural way:
    > char const * greeting = "Hello ";
    > greeting += "World";
    > But with std::string it will work:
    > std::string greeting = "Hello ";
    > greeting += "World";
    >
    > [1] string::string(char const * s);
    > string::string& string::eek:perator=(char const * s);


    Hmm, I think (hope) I understand (except the syntax of [1]) but I'm not
    sure. I did realize that I did not phrase my question precise enough.

    Please tell me if I'm wrong (actually, telling me when I'm right would
    also be nice):
    a) "some text" is the c-string (char const *) - an array of chars with a
    '\0' at the end.
    b) it is copied to str, which is an instance of a string object
    c) For me as a user of std::string, a string is not an array of chars
    anymore, but something else (what exactly I don't know yet but I hope I
    will learn as my study progresses). All I need to know for now is that I
    can easily do some stuff with it that would otherwise be more
    complicated (and potentially dangerous).
    d) Internally, std::string may (or may not) still use c-strings (like a
    class of imaginary numbers may still use floats).
     
    Mark S., Apr 19, 2009
    #12
  13. Mark S.

    James Kanze Guest

    Re: more questions...

    On Apr 19, 9:31 am, Obnoxious User <O...@127.0.0.1> wrote:
    > On Sun, 19 Apr 2009 08:10:51 +0200, Mark S. wrote:
    > > Obnoxious User wrote:
    > >> 'char *'-strings are old school C strings. Avoid them if
    > >> you're learning. Use only std::string. It's a complete
    > >> design failure that the fstream classes don't accept
    > >> std::string.

    > > Just to make sure: You mean that I should use c_str()
    > > whenever possible? I am still confused when "some text" is
    > > treated as a string and when as a char*. But I guess I'll
    > > figure it out eventually as time goes on.


    > Any text string in double quotes is of type 'char const *'.
    > "text"


    String literals have type char const[] in C++, not type char
    const*. They will, of course, convert to char const* in most
    contexts, they will also convert to std::string in many
    contexts, and to char* in a few special contexts.

    As for general rules as to when to use what, I'd argue that
    anytime you have to declare a variable, it should be
    std::string, and you'll use c_str() if you need to use a legacy
    interface. On the other hand, I don't have any problem with:
    std::ifstream in( "constantFileName" ) ;
    rather than
    std::ifstream in( std::string( "constantFileName" ).c_str() ) ;

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 19, 2009
    #13
  14. Mark S.

    James Kanze Guest

    Re: more questions...

    On Apr 19, 11:50 am, Obnoxious User <O...@127.0.0.1> wrote:
    > On Sun, 19 Apr 2009 10:45:00 +0200, Mark S. wrote:
    > > Obnoxious User wrote:
    > >> On Sun, 19 Apr 2009 08:10:51 +0200, Mark S. wrote:


    > >>> Obnoxious User wrote:
    > >>>> 'char *'-strings are old school C strings. Avoid them if
    > >>>> you're learning. Use only std::string. It's a complete
    > >>>> design failure that the fstream classes don't accept
    > >>>> std::string.
    > >>> Just to make sure: You mean that I should use c_str()
    > >>> whenever possible? I am still confused when "some text" is
    > >>> treated as a string and when as a char*. But I guess I'll
    > >>> figure it out eventually as time goes on.


    > >> Any text string in double quotes is of type 'char const *'.
    > >> "text"

    > > So when I have
    > > string str = "some text";
    > > there is actually some kind of cast happening?


    Formally, there is a conversion, yes. If you write
    string str( "some text" ) ;
    however, there isn't.

    > No. In this assignment[1]


    There is no assignment in his example.

    > 'str' will copy the c-string. std::string works with c-strings
    > transparently.


    Not totally. The conversion counts as a user defined
    conversion, if it's implicit. So if I write something like:

    class C
    {
    public:
    C( std::string const& ) ;
    } ;

    C aC = "some text" ;

    it won't compile.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 19, 2009
    #14
  15. Mark S.

    James Kanze Guest

    On Apr 19, 8:15 am, "Mark S." <> wrote:
    > James Kanze wrote:
    > > On the other hand, if some other serious error occured, so
    > > that you're abandonning processing anyway (and will report
    > > an error and maybe delete the file anyway), then it probably
    > > doesn't matter if the data in the file isn't valid, so you
    > > can allow the close in the destructor to do the job. (In
    > > this case, the destructor would typically be called as a
    > > result of stack unwinding from an exception.)


    > Hmm, but I guess it would still be nice to tell the user what
    > is going on.


    Presumably, you're going to tell him something, when you catch
    the exception. Presumably, too, if there was a problem serious
    enough to warrent an exception, the file you're writing probably
    won't be usable, even if the close succeeds, so there's no point
    in verifying whether it does succeed or not.

    > Of course it all depends on the situation, but I think I will
    > try to explicitly close files for now.


    It's never wrong. For input, as I said, it is usually
    superfluous.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 19, 2009
    #15
  16. Mark S.

    James Kanze Guest

    Re: some more file problems

    On Apr 19, 12:01 pm, "Mark S." <> wrote:
    > Hmm, I still have some trouble with files:


    Hmm, you overlooked one sentence in my previous posting:). You
    check the status of an input stream after every operation.

    > #include <fstream>
    > #include <iostream>
    > using namespace std;


    > int main()
    > {
    > string s;
    > ifstream in("E07.cpp");


    What happens if the open in the constructor fails?

    > getline(in, s);


    What happens if the getline fails (perhaps because the open
    beforehand failed)?

    > cout << s << endl;
    > in.seekg(0,ios::beg); // (1) going back to beginning of file
    > getline(in, s); // works!
    > cout << s << endl;
    > in.close();


    > int i = 0, j = 0;
    > ifstream in2("E07.cpp");
    > while(getline(in2, s))
    > i++;
    > in2.seekg(0,ios::beg); // (2) does not work
    > while(getline(in2, s))
    > j++;
    > cout << j << endl; // j is still 0!
    > }


    > - Why does (1) work, but (2) doesn't???


    Because in (2), you've reached the end of file. An operation
    failed, the stream object memorizes the error until you
    explicitly reset it.

    > More importantly, how do I get
    > it to work without opening the file a second time?


    istream::clear.

    > - But in case I do want to open a file, how can I open the same file
    > with the same identifier?
    > ifstream in("test.cpp");
    > in.close; // works
    > in.open // does not work
    > ifstream in("test.cpp"); // also doesn't work of course (double
    > declaration of "in")


    You'd have to give the identifier a second time.

    In addition, IIRC, there was an oversight in the standard, and
    the sequence close and open do not reset any of the error bits.
    Including the fact that the last input failed because you'd
    reached end of file. So you likely need a clear between the
    close and the open.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 19, 2009
    #16
  17. Mark S.

    Mark S. Guest

    Re: some more file problems

    James Kanze wrote:
    > On Apr 19, 12:01 pm, "Mark S." <> wrote:
    >> Hmm, I still have some trouble with files:

    >
    > Hmm, you overlooked one sentence in my previous posting:). You
    > check the status of an input stream after every operation.

    I'm sorry, but I have read the posts two more times now but I don't know
    which sentence you are referring to.

    >> #include <fstream>
    >> #include <iostream>
    >> using namespace std;

    >
    >> int main()
    >> {
    >> string s;
    >> ifstream in("E07.cpp");

    >
    > What happens if the open in the constructor fails?
    >
    >> getline(in, s);

    >
    > What happens if the getline fails (perhaps because the open
    > beforehand failed)?

    So you mean additional error checking is necessary? What would be the
    standard way of doing this?

    >> cout << s << endl;
    >> in.seekg(0,ios::beg); // (1) going back to beginning of file
    >> getline(in, s); // works!
    >> cout << s << endl;
    >> in.close();

    >
    >> int i = 0, j = 0;
    >> ifstream in2("E07.cpp");
    >> while(getline(in2, s))
    >> i++;
    >> in2.seekg(0,ios::beg); // (2) does not work
    >> while(getline(in2, s))
    >> j++;
    >> cout << j << endl; // j is still 0!
    >> }

    >
    >> - Why does (1) work, but (2) doesn't???

    >
    > Because in (2), you've reached the end of file. An operation
    > failed, the stream object memorizes the error until you
    > explicitly reset it.
    >
    >> More importantly, how do I get
    >> it to work without opening the file a second time?

    >
    > istream::clear.

    Alright, I have added the line ( in.clear(); ). But sadly, the result is
    the same. :-(

    >> - But in case I do want to open a file, how can I open the same file
    >> with the same identifier?
    >> ifstream in("test.cpp");
    >> in.close; // works
    >> in.open // does not work
    >> ifstream in("test.cpp"); // also doesn't work of course (double
    >> declaration of "in")

    >
    > You'd have to give the identifier a second time.

    Sorry, I don't know what you mean by that.
     
    Mark S., Apr 23, 2009
    #17
  18. Mark S.

    James Kanze Guest

    Re: some more file problems

    On Apr 23, 8:35 am, "Mark S." <> wrote:
    > James Kanze wrote:
    > > On Apr 19, 12:01 pm, "Mark S." <> wrote:
    > >> Hmm, I still have some trouble with files:


    > > Hmm, you overlooked one sentence in my previous posting:).
    > > You check the status of an input stream after every
    > > operation.


    > I'm sorry, but I have read the posts two more times now but I
    > don't know which sentence you are referring to.


    The sentence "In practice, when inputting, you're checking
    the status after each input anyway;". You can't use the result
    of input until you've verified that the input actually worked.

    > >> #include <fstream>
    > >> #include <iostream>
    > >> using namespace std;


    > >> int main()
    > >> {
    > >> string s;
    > >> ifstream in("E07.cpp");


    > > What happens if the open in the constructor fails?


    > >> getline(in, s);


    > > What happens if the getline fails (perhaps because the open
    > > beforehand failed)?


    > So you mean additional error checking is necessary?


    Yes. If the file wasn't present, or was empty, or didn't
    contain a newline character, getline will fail. And the
    contents of s will not be signficant.

    > What would be the standard way of doing this?


    if ( in ) {
    // succeeded...
    } else {
    // failed...
    }

    Usually, you'll want to read more than just one line, and would
    write something like:

    while ( std::getline( in, s ) ) {
    // ...
    }

    The most frequent reason for failure is that you've reached the
    end of file, at least in the case of getline. For formatting
    input, the issue is more complicated, since you can also have
    format errors (i.e. you're reading an int, and the input is
    "abc"). You can distinguish to some degree why the operation
    failed by checking individual status bits:
    in.bad() A hardware error. Not much you can do about
    it (and many applications just treat it as
    end of file).

    in.fail() && ! in.eof()
    A format error in the input. Tell the user.
    In addition, you might want to try to
    resynchronize and continue, by clearing the
    error ("in.clear()"), reading data until you
    think you'r resynchronized, and trying to
    continue.

    in.fail() && in.eof()
    No more data was present. (Usually. There
    are a few special cases where a format error
    can also result in this situation.)

    > >> cout << s << endl;
    > >> in.seekg(0,ios::beg); // (1) going back to beginning of file
    > >> getline(in, s); // works!
    > >> cout << s << endl;
    > >> in.close();


    > >> int i = 0, j = 0;
    > >> ifstream in2("E07.cpp");
    > >> while(getline(in2, s))
    > >> i++;
    > >> in2.seekg(0,ios::beg); // (2) does not work
    > >> while(getline(in2, s))
    > >> j++;
    > >> cout << j << endl; // j is still 0!
    > >> }


    > >> - Why does (1) work, but (2) doesn't???


    > > Because in (2), you've reached the end of file. An
    > > operation failed, the stream object memorizes the error
    > > until you explicitly reset it.


    > >> More importantly, how do I get it to work without opening
    > >> the file a second time?


    > > istream::clear.


    > Alright, I have added the line ( in.clear(); ). But sadly, the
    > result is the same. :-(


    Where did you add it. If you added it before the seek, it
    should work.

    > >> - But in case I do want to open a file, how can I open the same file
    > >> with the same identifier?
    > >> ifstream in("test.cpp");
    > >> in.close; // works
    > >> in.open // does not work
    > >> ifstream in("test.cpp"); // also doesn't work of course (double
    > >> declaration of "in")


    > > You'd have to give the identifier a second time.


    > Sorry, I don't know what you mean by that.


    Me neither. Either some context is missing, or I was thinking
    of something else. If you want to open a file a second time:

    std::ifstream in( "test.cpp" ) ;
    // ...
    in.close() ;
    in.clear() ;
    in.open( "test.cpp" ) ;
    // ...

    The clear is formally necessary according to the current
    standard. It won't be necessary in the next version of the
    standard, and I think that some current implementations don't
    require it either. (It doesn't make sense. close, followed by
    open, means you're starting over.)

    Alternatively, you can use a different variable:

    {
    std::ifstream in( "test.cpp" ) ;
    // ...
    }
    {
    std::ifstream in( "test.cpp" ) ;
    // ...
    }

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 23, 2009
    #18
  19. Mark S.

    Mark S. Guest

    Re: some more file problems

    James Kanze wrote:
    > On Apr 23, 8:35 am, "Mark S." <> wrote:
    >> James Kanze wrote:
    >>> On Apr 19, 12:01 pm, "Mark S." <> wrote:
    >>>> Hmm, I still have some trouble with files:

    >
    >>> Hmm, you overlooked one sentence in my previous posting:).
    >>> You check the status of an input stream after every
    >>> operation.

    >
    >> I'm sorry, but I have read the posts two more times now but I
    >> don't know which sentence you are referring to.

    >
    > The sentence "In practice, when inputting, you're checking
    > the status after each input anyway;". You can't use the result
    > of input until you've verified that the input actually worked.
    >
    >>>> #include <fstream>
    >>>> #include <iostream>
    >>>> using namespace std;

    >
    >>>> int main()
    >>>> {
    >>>> string s;
    >>>> ifstream in("E07.cpp");

    >
    >>> What happens if the open in the constructor fails?

    >
    >>>> getline(in, s);

    >
    >>> What happens if the getline fails (perhaps because the open
    >>> beforehand failed)?

    >
    >> So you mean additional error checking is necessary?

    >
    > Yes. If the file wasn't present, or was empty, or didn't
    > contain a newline character, getline will fail. And the
    > contents of s will not be signficant.
    >
    >> What would be the standard way of doing this?

    >
    > if ( in ) {
    > // succeeded...
    > } else {
    > // failed...
    > }

    Ahh, that is simple enough. :)

    > Usually, you'll want to read more than just one line, and would
    > write something like:
    >
    > while ( std::getline( in, s ) ) {
    > // ...
    > }

    Yes, that's what I had so far.

    > The most frequent reason for failure is that you've reached the
    > end of file, at least in the case of getline. For formatting
    > input, the issue is more complicated, since you can also have
    > format errors (i.e. you're reading an int, and the input is
    > "abc"). You can distinguish to some degree why the operation
    > failed by checking individual status bits:
    > in.bad() A hardware error. Not much you can do about
    > it (and many applications just treat it as
    > end of file).
    >
    > in.fail() && ! in.eof()
    > A format error in the input. Tell the user.
    > In addition, you might want to try to
    > resynchronize and continue, by clearing the
    > error ("in.clear()"), reading data until you
    > think you'r resynchronized, and trying to
    > continue.
    >
    > in.fail() && in.eof()
    > No more data was present. (Usually. There
    > are a few special cases where a format error
    > can also result in this situation.)

    Thank you!

    >>>> cout << s << endl;
    >>>> in.seekg(0,ios::beg); // (1) going back to beginning of file
    >>>> getline(in, s); // works!
    >>>> cout << s << endl;
    >>>> in.close();

    >
    >>>> int i = 0, j = 0;
    >>>> ifstream in2("E07.cpp");
    >>>> while(getline(in2, s))
    >>>> i++;
    >>>> in2.seekg(0,ios::beg); // (2) does not work
    >>>> while(getline(in2, s))
    >>>> j++;
    >>>> cout << j << endl; // j is still 0!
    >>>> }

    >
    >>>> - Why does (1) work, but (2) doesn't???

    >
    >>> Because in (2), you've reached the end of file. An
    >>> operation failed, the stream object memorizes the error
    >>> until you explicitly reset it.

    >
    >>>> More importantly, how do I get it to work without opening
    >>>> the file a second time?

    >
    >>> istream::clear.

    >
    >> Alright, I have added the line ( in.clear(); ). But sadly, the
    >> result is the same. :-(

    >
    > Where did you add it. If you added it before the seek, it
    > should work.

    Ahh, that was indeed the error. istream::clear had to come before
    istream::seekg and istream::close.

    >>>> - But in case I do want to open a file, how can I open the same file
    >>>> with the same identifier?
    >>>> ifstream in("test.cpp");
    >>>> in.close; // works
    >>>> in.open // does not work
    >>>> ifstream in("test.cpp"); // also doesn't work of course (double
    >>>> declaration of "in")

    >
    >>> You'd have to give the identifier a second time.

    >
    >> Sorry, I don't know what you mean by that.

    >
    > Me neither. Either some context is missing, or I was thinking
    > of something else. If you want to open a file a second time:
    >
    > std::ifstream in( "test.cpp" ) ;
    > // ...
    > in.close() ;
    > in.clear() ;
    > in.open( "test.cpp" ) ;
    > // ...

    Ahh, alright. This works as well now!

    > The clear is formally necessary according to the current
    > standard. It won't be necessary in the next version of the
    > standard, and I think that some current implementations don't
    > require it either. (It doesn't make sense. close, followed by
    > open, means you're starting over.)
    >
    > Alternatively, you can use a different variable:
    >
    > {
    > std::ifstream in( "test.cpp" ) ;
    > // ...
    > }
    > {
    > std::ifstream in( "test.cpp" ) ;
    > // ...
    > }

    I'm sorry, but I don't see a different variable here. But I think I got
    it anyway. Again, thank you!
     
    Mark S., Apr 23, 2009
    #19
    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. John
    Replies:
    10
    Views:
    10,059
    Buster Copley
    Jul 14, 2003
  2. Joe
    Replies:
    4
    Views:
    7,755
    Chris Theis
    Jan 22, 2004
  3. Jim Phelps
    Replies:
    1
    Views:
    1,729
    Karl Heinz Buchegger
    Jan 21, 2004
  4. Christopher Benson-Manica

    ifstream/getline

    Christopher Benson-Manica, Apr 1, 2004, in forum: C++
    Replies:
    15
    Views:
    28,540
    Leor Zolman
    Apr 1, 2004
  5. shakeelsultan

    Exact synatx required...!

    shakeelsultan, Feb 18, 2007, in forum: VHDL
    Replies:
    1
    Views:
    506
    rgurrola
    Feb 20, 2007
Loading...

Share This Page