reading a file into std::string

Discussion in 'C++' started by arnuld, Aug 8, 2011.

  1. arnuld

    arnuld Guest

    I want to read a file into std::string. I am basically a C Programmer so
    it was quite hard for me to understand how to do it in C++. I did C++
    long time back (if you guys remember my name but I do remember Shiva and
    Victor Bazarov and others).

    I googled for it and this is the best what I could come up with. Do you
    guys have any suggestion for improvement ? and whether this is really a
    correct C++ program. (Compiled with "g++ -ansi -pedantic -Wall -Wextra")



    #include <iostream>
    #include <fstream>
    #include <string>


    int main()
    {
    std::string my_contents, tmp_contents;
    std::ifstream my_file("reference.cpp");
    if(!my_file)
    {
    std::cerr << "Error Opening file" << std::endl;
    exit(EXIT_FAILURE);
    }

    while(my_file)
    {
    std::getline(my_file, tmp_contents);
    my_contents += tmp_contents;
    my_contents += "\n";
    }

    std::cout << "String contents are: "<< "\n"
    << my_contents << std::endl;

    my_file.close();

    return 0;
    }





    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 8, 2011
    #1
    1. Advertising

  2. arnuld

    Marc Guest

    arnuld wrote:

    > I want to read a file into std::string. I am basically a C Programmer so
    > it was quite hard for me to understand how to do it in C++. I did C++
    > long time back (if you guys remember my name but I do remember Shiva and
    > Victor Bazarov and others).

    [...]
    > std::string my_contents, tmp_contents;
    > std::ifstream my_file("reference.cpp");
    > if(!my_file)
    > {
    > std::cerr << "Error Opening file" << std::endl;
    > exit(EXIT_FAILURE);
    > }
    >
    > while(my_file)
    > {
    > std::getline(my_file, tmp_contents);
    > my_contents += tmp_contents;
    > my_contents += "\n";
    > }


    You might as well use std::getline(my_file, my_contents, '\0'),
    assuming there is no null character in your file. Not that it is a
    good solution, but at least you don't have a loop.
     
    Marc, Aug 8, 2011
    #2
    1. Advertising

  3. arnuld

    red floyd Guest

    On 8/8/2011 7:05 AM, Sam wrote:
    > Sam writes:
    >
    >> arnuld writes:
    >>
    >>> I want to read a file into std::string. I am basically a C Programmer so
    >>> it was quite hard for me to understand how to do it in C++. I did C++
    >>> long time back (if you guys remember my name but I do remember Shiva and
    >>> Victor Bazarov and others).
    >>>
    >>> I googled for it and this is the best what I could come up with. Do you
    >>> guys have any suggestion for improvement ? and whether this is really a
    >>> correct C++ program. (Compiled with "g++ -ansi -pedantic -Wall -Wextra")

    >>
    >> Your program is basically a C program. Here's a C++ program.
    >>
    >> #include <iostream>
    >> #include <fstream>
    >> #include <sstream>
    >>
    >> int main()
    >> {
    >> std::eek:stringstream o;
    >>
    >> o << std::ifstream("reference.cpp").rdbuf();
    >>
    >> std::string my_contents= o.str();
    >>
    >> return 0;
    >> }

    >
    > … Or, here's a slightly more efficient version.
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iterator>
    > #include <algorithm>
    >
    > int main()
    > {
    > std::string my_contents;
    >
    > std::copy(std::istreambuf_iterator<char>(std::ifstream("reference.cpp").rdbuf()),
    >
    > std::istreambuf_iterator<char>(),
    > std::back_insert_iterator<std::string>(my_contents));
    >
    > return 0;
    > }
    >
    >



    Avoid the copy.


    #include <iostream>
    #include <fstream>
    #include <string>
    #include <iterator>

    int main()
    {
    // note: extra parens on the constructor args to
    // avoid potential "Most Vexing Parse" issues
    std::string my_contents(
    std::istreambuf_iterator<char>(
    (std::ifstream("reference.cpp").rdbuf())),
    (std::istreambuf_iterator<char>()));
    }
     
    red floyd, Aug 8, 2011
    #3
  4. arnuld

    arnuld Guest

    > On Mon, 08 Aug 2011 13:23:49 -0700, red floyd wrote:

    > Avoid the copy.
    >
    >
    > #include <iostream>
    > #include <fstream>
    > #include <string>
    > #include <iterator>
    >
    > int main()
    > {
    > // note: extra parens on the constructor args to
    > // avoid potential "Most Vexing Parse" issues
    > std::string my_contents(
    > std::istreambuf_iterator<char>(
    > (std::ifstream("reference.cpp").rdbuf())),
    > (std::istreambuf_iterator<char>()));
    > }



    Can you please tell me in brief how it works. 2nd, you said "Avoid the
    copy", so your program does not copy ?

    All I can see is its a template. What about error checking whether file
    was opened successfully or not, we are nto even closing the file after we
    finish ? I have Stroustrup 3/e in my hands, checking out what rdbuf()
    does from section 21.6.3, page 644.


    --
    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 9, 2011
    #4
  5. arnuld

    red floyd Guest

    On 8/8/2011 10:13 PM, arnuld wrote:
    >> On Mon, 08 Aug 2011 13:23:49 -0700, red floyd wrote:

    >
    >> Avoid the copy.
    >>
    >>
    >> #include<iostream>
    >> #include<fstream>
    >> #include<string>
    >> #include<iterator>
    >>
    >> int main()
    >> {
    >> // note: extra parens on the constructor args to
    >> // avoid potential "Most Vexing Parse" issues
    >> std::string my_contents(
    >> std::istreambuf_iterator<char>(
    >> (std::ifstream("reference.cpp").rdbuf())),
    >> (std::istreambuf_iterator<char>()));
    >> }

    >
    >
    > Can you please tell me in brief how it works. 2nd, you said "Avoid the
    > copy", so your program does not copy ?


    The example I was referring to had constructed an empty string, and then
    copied the file into it.

    My example creates the string with the contents of the file, by using
    a constructor that takes two iterators.

    In actual practice, there won't be much difference, but one-upmanship
    sometimes comes into play on this newsgroup! <grin>

    > All I can see is its a template. What about error checking whether file
    > was opened successfully or not, we are nto even closing the file after we
    > finish ? I have Stroustrup 3/e in my hands, checking out what rdbuf()
    > does from section 21.6.3, page 644.


    It is "template" code. Error checking, etc... is left as an exercise
    for the reader.

    rdbuf() returns the streambuf underlying the fstream.
     
    red floyd, Aug 9, 2011
    #5
  6. arnuld

    arnuld Guest

    > On Mon, 08 Aug 2011 23:12:30 -0700, red floyd wrote:

    > My example creates the string with the contents of the file, by using a
    > constructor that takes two iterators.


    Chapter Strings, Section 20.3.4 I don't see any constructir which takes 2
    arguments. If I go to section 16.3.4 then it does have two iterators in a
    constructor but that is std::vector not std::string


    > It is "template" code. Error checking, etc... is left as an exercise
    > for the reader.


    you mean this code will be real-life code based on the ideas you have
    given me:

    #include <iostream>
    #include <fstream>
    #include <string>


    int main()
    {
    std::ifstream my_file("reference.cpp");
    if(!my_file)
    {
    std::cerr << "Error Opening file" << std::endl;
    exit(EXIT_FAILURE);
    }

    std::string my_contents(std::istreambuf_iterator<char>(my_file.rdbuf()),
    (std::istreambuf_iterator<char>()));

    std::cout << "String contents are: "<< "\n"
    << my_contents << std::endl;

    my_file.close();

    return 0;
    }

    as usual compiled with "gcc -ansi -pedantic -Wall -Wextra" and it
    compiles and runs fine.



    --
    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 9, 2011
    #6
  7. Sam <> wrote:
    > Your program is basically a C program. Here's a C++ program.


    I think the std::getline() with a null line terminator is a much simpler
    and better solution.
     
    Juha Nieminen, Aug 9, 2011
    #7
  8. arnuld

    Marc Guest

    Juha Nieminen wrote:

    > Sam <> wrote:
    >> Your program is basically a C program. Here's a C++ program.

    >
    > I think the std::getline() with a null line terminator is a much simpler
    > and better solution.


    ostream::eek:perator<<(streambuf*) has the advantage that it doesn't need
    to check characters one by one. Of all the solutions in the thread, it
    looks like the one most likely to perform batch copies.

    (of course anything C++ will be much slower than a version with mmap)
     
    Marc, Aug 9, 2011
    #8
  9. arnuld

    arnuld Guest

    > On Tue, 09 Aug 2011 11:26:29 +0000, Juha Nieminen wrote:

    > I think the std::getline() with a null line terminator is a much
    > simpler and better solution.


    Stroustrup, section 20.3.15, page 598

    The getline() function reads a line terminated by eol into its
    string, expanding the string as needed to hold the line. If no eol
    argument is provided, a newline '\n' is used as the delimiter. The line
    terminator is removed from the stream but not entered into string.

    where string = 2nd argument, eol = 3rd argument

    now my point is when you give '\0' (its called null or NULL ?) as 3rd
    argument which is not present in the input stream, what will be its
    behavior ?

    (1) will getline() keep on looking for it till its reaches EOF (End of
    File) and read whole file into the string

    (2) If I give anything which is not present in the input e.g. '#' will it
    behave the same ?




    --
    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 9, 2011
    #9
  10. arnuld

    red floyd Guest

    On 8/8/2011 11:45 PM, arnuld wrote:
    >> On Mon, 08 Aug 2011 23:12:30 -0700, red floyd wrote:

    >
    >> My example creates the string with the contents of the file, by using a
    >> constructor that takes two iterators.

    >
    > Chapter Strings, Section 20.3.4 I don't see any constructir which takes 2
    > arguments. If I go to section 16.3.4 then it does have two iterators in a
    > constructor but that is std::vector not std::string
    >


    ISO/IEC 14882:2003, sections 21.3/6 [lib.basic.string] and
    21.3.1/14 [lib.string.cons]

    template<class InputIterator>
    basic_string(InputIterator begin, InputIterator end,
    const Allocator& a = Allocator());
     
    red floyd, Aug 9, 2011
    #10
  11. arnuld

    red floyd Guest

    On 8/8/2011 11:45 PM, arnuld wrote:
    > you mean this code will be real-life code based on the ideas you have
    > given me:
    >
    > #include<iostream>
    > #include<fstream>
    > #include<string>
    >
    >
    > int main()
    > {
    > std::ifstream my_file("reference.cpp");
    > if(!my_file)
    > {
    > std::cerr<< "Error Opening file"<< std::endl;
    > exit(EXIT_FAILURE);
    > }
    >
    > std::string my_contents(std::istreambuf_iterator<char>(my_file.rdbuf()),
    > (std::istreambuf_iterator<char>()));
    >
    > std::cout<< "String contents are:"<< "\n"
    > << my_contents<< std::endl;
    >
    > my_file.close();
    >
    > return 0;
    > }


    Just an FYI, the my_file.close() is not required, as the ifstream
    destructor will close it for you.
     
    red floyd, Aug 9, 2011
    #11
  12. arnuld

    red floyd Guest

    On 8/8/2011 11:45 PM, arnuld wrote:

    > you mean this code will be real-life code based on the ideas you have
    > given me:
    >
    > #include<iostream>
    > #include<fstream>
    > #include<string>
    >
    >
    > int main()
    > {
    > std::ifstream my_file("reference.cpp");
    > if(!my_file)
    > {
    > std::cerr<< "Error Opening file"<< std::endl;
    > exit(EXIT_FAILURE);
    > }
    >
    > std::string my_contents(std::istreambuf_iterator<char>(my_file.rdbuf()),
    > (std::istreambuf_iterator<char>()));
    >
    > std::cout<< "String contents are:"<< "\n"
    > << my_contents<< std::endl;
    >
    > my_file.close();
    >
    > return 0;
    > }
    >
    > as usual compiled with "gcc -ansi -pedantic -Wall -Wextra" and it
    > compiles and runs fine.

    Technically. you need to #include <cstdlib> to define EXIT_FAILURE.

    In actual practice, obviously one of <iostream>, <fstream>, or <string>
    is including it.

    Also, I believe std::endl is defined in <ostream>. In C++11 <iostream>
    covers that, but in C++03, <iostream> does not officially include
    <ostream>, though as far as I know, all known C++ compilers do the
    nested include.
     
    red floyd, Aug 9, 2011
    #12
  13. Marc <> wrote:
    > (of course anything C++ will be much slower than a version with mmap)


    For a more portable solution, the fastest method would probably be to
    resolve the size of the input file (I think using fseek and ftell is
    portable enough for this, although I don't know if it's technically a
    100% portable method, but it does work in most systems I know of), then
    allocate a string of that size and dump the entire file into it using
    fread (which is faster than std::istream::read in most systems).

    OTOH I don't remember now if the standard guarantees that std::string
    will allocate a contiguous block of memory. Probably not. That would be
    a problem. You could use std::vector<char> which is guaranteed to be
    contiguous, but then you don't have the std::string functions to operate
    on it. However, std::vector<char> is often enough for most purposes.
    (Assigning a std::string from the std::vector<char> would be inefficient
    because it would temporarily double the memory requirement, and there
    would be basically useless copying of all the data.)
     
    Juha Nieminen, Aug 9, 2011
    #13
  14. arnuld

    Marc Guest

    Juha Nieminen wrote:

    > OTOH I don't remember now if the standard guarantees that std::string
    > will allocate a contiguous block of memory. Probably not. That would be
    > a problem.


    C++0X does. I can't find such a guarantee in C++03, but it is probably
    ok to assume it is there...
     
    Marc, Aug 9, 2011
    #14
  15. arnuld

    red floyd Guest

    On 8/9/2011 9:47 AM, Marc wrote:
    > Juha Nieminen wrote:
    >
    >> OTOH I don't remember now if the standard guarantees that std::string
    >> will allocate a contiguous block of memory. Probably not. That would be
    >> a problem.

    >
    > C++0X does. I can't find such a guarantee in C++03, but it is probably
    > ok to assume it is there...


    It's not guaranteed in C++03, but I believe all current implementations
    do so.
     
    red floyd, Aug 9, 2011
    #15
  16. arnuld

    arnuld Guest

    > On Tue, 09 Aug 2011 09:26:58 -0700, red floyd wrote:

    > ISO/IEC 14882:2003, sections 21.3/6 [lib.basic.string] and
    > 21.3.1/14 [lib.string.cons]


    > template<class InputIterator>
    > basic_string(InputIterator begin, InputIterator end,
    > const Allocator& a = Allocator());


    I have n3242.pdf and in section 21.3 (page 624) I can't find this (may
    template syntax is too alien for me). 2nd, even if its there, we used 2
    arguments unlike 3 mentioned here. I assume it will have some default
    value.






    --
    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 10, 2011
    #16
  17. arnuld

    arnuld Guest

    > On Tue, 09 Aug 2011 09:33:41 -0700, red floyd wrote:


    > Technically. you need to #include <cstdlib> to define EXIT_FAILURE.


    I wanted to do it C++ way, how C++ defines exit for failure/success.


    > In actual practice, obviously one of <iostream>, <fstream>, or <string>
    > is including it.



    > Also, I believe std::endl is defined in <ostream>. In C++11 <iostream>
    > covers that, but in C++03, <iostream> does not officially include
    > <ostream>, though as far as I know, all known C++ compilers do the
    > nested include.


    That is strange. I thought both <istream> and <ostream> were children of
    parent class <iostream> and they will inherit std::endl from <iostream>.






    --
    -- arnuld
    www.LispMachine.Wordpress.com
     
    arnuld, Aug 10, 2011
    #17
  18. arnuld

    Bo Persson Guest

    arnuld wrote:
    >> On Tue, 09 Aug 2011 09:26:58 -0700, red floyd wrote:

    >
    >> ISO/IEC 14882:2003, sections 21.3/6 [lib.basic.string] and
    >> 21.3.1/14 [lib.string.cons]

    >
    >> template<class InputIterator>
    >> basic_string(InputIterator begin, InputIterator end,
    >> const Allocator& a = Allocator());

    >
    > I have n3242.pdf and in section 21.3 (page 624) I can't find this
    > (may template syntax is too alien for me). 2nd, even if its there,
    > we used 2 arguments unlike 3 mentioned here. I assume it will have
    > some default value.


    It is a member (constructor). See page 629 and bottom of page 634.



    Bo Persson
     
    Bo Persson, Aug 10, 2011
    #18
  19. arnuld

    red floyd Guest

    On 8/10/2011 3:58 AM, arnuld wrote:
    >> On Tue, 09 Aug 2011 09:26:58 -0700, red floyd wrote:

    >
    >> ISO/IEC 14882:2003, sections 21.3/6 [lib.basic.string] and
    >> 21.3.1/14 [lib.string.cons]

    >
    >> template<class InputIterator>
    >> basic_string(InputIterator begin, InputIterator end,
    >> const Allocator& a = Allocator());

    >
    > I have n3242.pdf and in section 21.3 (page 624) I can't find this (may
    > template syntax is too alien for me). 2nd, even if its there, we used 2
    > arguments unlike 3 mentioned here. I assume it will have some default
    > value.


    The section numbering of n3242 (C++11 draft) differs from the official
    2003 Standard.
     
    red floyd, Aug 10, 2011
    #19
  20. arnuld

    Nobody Guest

    On Wed, 10 Aug 2011 12:13:33 +0000, arnuld wrote:

    > That is strange. I thought both <istream> and <ostream> were children of
    > parent class <iostream> and they will inherit std::endl from <iostream>.


    <istream>, <ostream> and <iostream> are headers, not classes, although
    classes with those names exist.

    Also, std::endl() is a function, not a method.
     
    Nobody, Aug 11, 2011
    #20
    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. Peter Jansson
    Replies:
    5
    Views:
    6,356
    Ivan Vecerina
    Mar 17, 2005
  2. Vinu
    Replies:
    4
    Views:
    377
    Jim Langston
    Jul 7, 2005
  3. Fei Liu
    Replies:
    9
    Views:
    457
  4. Jeffrey Walton
    Replies:
    10
    Views:
    956
    Mathias Gaunard
    Nov 26, 2006
  5. Sergey Lukoshkin
    Replies:
    7
    Views:
    465
    Daniel Pitts
    Jul 9, 2010
Loading...

Share This Page