CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Reading a file using istream_iterator

    I have read the latest post about istream_iterator here and this leads to another question.
    I have a file which contains char sequences ("strings"), separated by \0.
    I'd like to be able to read the file using istream_iterators. I have been able to accomplish this when the delimiter in the file is \n rather than \0.
    Could someone please help me out?
    Code:
    // using istringstream instead of ifstream for this sample code
    std::istringstream iss(
    //  "text10\0text20\0text30\0text40\0text50\0text60\0" // this does not work
      "text10\ntext20\ntext30\ntext40\ntext50\ntext60\n" // this works
    );
    
    int main()
    {
        std::istream_iterator<std::string> it_first(iss);
        std::istream_iterator<std::string> it_last;
        std::ostream_iterator<std::string> it_out(std::cout, " ");
        std::copy(it_first, it_last, it_out);
        std::cout << std::endl;
    }

  2. #2
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Reading a file using istream_iterator

    well, there are two reasons why your code won't work:

    first, the istream_iterator<T> invokes T's operator>> and std::string operator>> uses std::isspace ( with the stream locale ) as a separator test, that in turn always return false for the null character. Hence, your input stringstream should extract a single string with multiple null-characters inside.

    actually, the line "std::istringstream iss( "text10\0text20\0text30\0text40\0text50\0text60\0" );" invokes the converting std::string constructor which simply copy the first null terminated string in the stringstream; so, in the end a single "text10" string will be extracted.

    Anyway, I suppose your real code uses a file stream instead, doesn't it ?

    if yes, I'd use the std::getline( some_istream, some_string_buffer, 0 ) function in a loop instead ...

  3. #3
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Reading a file using istream_iterator

    Well yes, at the moment the sample code always only extracts the first string "text10".

    I'd like to use a real file, but even with my sample code and using std::getline on it I did not get the desired result.
    I'll make a new test program that works on a file.

  4. #4
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Reading a file using istream_iterator

    Hey, that kind of looks like my code!

    Anywhoo, AFAIK, and according to this, istream_iterator, is just an iterator adaptor, that uses operator>> internally, which means that if you can't write this anyways:

    Code:
    #include <iostream>
    #include <sstream>
    #include <iterator>
    
    // using istringstream instead of ifstream for this sample code
    std::istringstream iss(
      "text10\0text20\0text30\0text40\0text50\0text60\0" // this does not work
    //  "text10\ntext20\ntext30\ntext40\ntext50\ntext60\n" // this works
    );
    
    int main()
    {
      std::string word;
      while (iss >> word)
      {
        std::cout << word << " ";
      }
    }
    Then istream_iterator, by design, can't work.
    Unless I'm mistaken, isn't '\0' universally recognized a stream terminator? I may be mistaken (I AM!), but I believe that unless you clear that '\0' after each read, than no solution can work. Even this fails:

    [EDIT]: See super bonzo's reply as to why this doesn't actually work.

    Code:
    #include <iostream>
    #include <sstream>
    #include <iterator>
    
    // using istringstream instead of ifstream for this sample code
    std::istringstream iss(
      "text10\0text20\0text30\0text40\0text50\0text60\0" // this does not work
    //  "text10\ntext20\ntext30\ntext40\ntext50\ntext60\n" // this works
    );
    
    int main()
    {
      std::string word;
      while (getline(iss, word, '\0'))
      {
        std::cout << word << " ";
      }
    }
    Last edited by monarch_dodra; January 17th, 2012 at 11:39 AM.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  5. #5
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Reading a file using istream_iterator

    <EDIT: uhm, the following is in reply to post#3, of course>

    yes, and I already explained why getline does not work with your code, it's because of the way you're initializing the stringstream. Consider the following:

    Code:
    std::istringstream iss( "text10\0text20\0text30\0text40\0text50\0text60\0" );
    
    int main()
    {
    	std::string buffer;
    
    	while( std::getline( iss, buffer, char() ) )
    	{
    		std::cout << buffer << std::endl;
    	}
    }
    this won't work, outputting "text10". But this:

    Code:
    char iss_buf[] = "text10\0text20\0text30\0text40\0text50\0text60\0";
    std::istringstream iss( std::string( iss_buf, sizeof(iss_buf) ) );
    
    int main()
    {
    	std::string buffer;
    
    	while( std::getline( iss, buffer, char() ) )
    	{
    		std::cout << buffer << std::endl;
    	}
    }
    works as expected.
    Last edited by superbonzo; January 17th, 2012 at 10:27 AM.

  6. #6
    Join Date
    Mar 2008
    Location
    Turin / Italy
    Posts
    178

    Re: Reading a file using istream_iterator

    Quick test on a real file.
    Code:
    #include <iostream>
    #include <fstream>
    #include <iterator>
    #include <string>
    
    class line {
    	std::string data;
    public:
    	friend std::istream &operator>>(std::istream &is, line &l) {
    		std::getline(is, l.data,'\0');
    		return is;
    	}
    	operator std::string() const { return data; }    
    };
    
    
    
    int main()
    {
    	std::ifstream in("in.txt");
    	std::istream_iterator<line> it_first(in);
    	std::istream_iterator<line> it_last;
    	std::ostream_iterator<std::string> it_out(std::cout, "\n");
    	std::copy(it_first, it_last, it_out);
    	in.close();
    	std::cout << std::endl;
    }
    Seems to work.

  7. #7
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Reading a file using istream_iterator

    Quote Originally Posted by monarch_dodra View Post
    Even this fails:
    that fails for the reason explained in post #2

  8. #8
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: Reading a file using istream_iterator

    Thanks superbonzo, I think I understand. I'll give it a try in my real prog.

    monarch_dodra, the sample code is indeed a copy of yours. The other thread with istream_operator motivated my to give the istream_iterator a try and I started with your sample, modifying it, testing around and get to no solution.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured