Help with ifstream::getline

Started by
7 comments, last by rip-off 16 years, 7 months ago
Hi Everybody :) I have a question about ifstream::getline Lets say I have the following text file: ------------- 1234567 < this is the first line of the txt file hello world < this is the last line of the txt file ------------- my code is

  std::ifstream ft;
  ft.open(...);

  char buff[25];
  while(!ft.eof())
  {
   ft.getline(buff,3);
   cout<<buff<<endl;

  }

At the first iteration of the loop, when getline(buff,3) reads a line which contains more characters than the buffer I have specified, 3, than the next iteration getline(buff,3) does not read anything, i get an empty buffer even though there are more lines, and this loop continues forever. Do I need to clean the buffer or something like that? Thanks
;)
Advertisement
Quote: from "The C plus plus Standard Library"
If they read lines with more than count-1 characters, they set failbit.


I believe it's std::ios_base::failbit. I would guess it keeps reading the same line over and over?

p.s. why can't I use the plus symbol?!?
If the line is larger than the buffer, the stream will enter a "failed" state when you try to read it. You need to reset this failed state using ft.clear() on your stream. You can detect the failed state by calling ft.fail().
Don't use while(!file.eof()), the end of file bit is set only after a failed read (so your loop will execute one extra time).

Instead use the read operation itself in the condition:
while( std::getline(file,input) ) {}


Prefer the use of std::string for strings.

Also, since getline uses the last as the delimiter, but you probably meant to use '3'. If not please specify what you want to do.
Quote:Original post by rip-off
Also, since getline uses the last as the delimiter, but you probably meant to use '3'. If not please specify what you want to do.


istream::getline(char*, streamsize) uses the last as the number of characters to be read.
If all you want to do is to read a file and put the contents somewhere, you can use rdbuf(), like:

std::ifstream in("file.txt");  // Initializes the streamstd::cout << in.rdbuf();       // Sends stream read buffer to coutin.seekg(0);                   // Resets to beginning of buffer.in.clear();                    // Clears failbit and eofbit.


That should print the entire contents of "file.txt" verbatim. Drawback is that you
can't check the state of the stream. Always clear() and reset seekg(0) if you want to re-read the file.

Another alternative is to get the info character by character, like:

std::ifstream in("file.txt");  // Initializes the streamchar c;while(in.get(c)){    cout.put(c);}


The above lets you check stream state. Also, unless you really have to, using a character buffer with std::getline(,) instead of a std::string is asking for problems, as mentioned by rip-off.

As ToohrVyk (and rip-off, indirectly) mentioned, use the fail state for your conditional. Something like:

std::ifstream in("file.txt");std::string input;while (!in.fail())  // similarly, rip-off suggested 'while( std::getline(in,input) ){}'{    do something...}


If you have a lot of character or string manipulation, my personal preference is to use file operations as little as possible, and read the contents into a string buffer, and then use string methods for everything else. So you could do something like:

#include <fstream>#include <sstream>#include <string>std::string fileToString(const std::string& filename){    std::ostringstream out;    std::ifstream in(filename.c_str());    out << in.rdbuf();    return out.str();   }std::string strbuf = fileToString("file.txt");


Then you can use the rather rich facilities of std::string to manipulate strbuf. I use the name 'strbuf' loosely here, as it is just a string. This is not to be confused with the standard library 'stringbuf' and 'wstringbuf' that are specializations of the 'basic_stringbuf<>' template class.

--random

[Edited by - random_thinker on September 18, 2007 3:37:15 AM]
--random_thinkerAs Albert Einstein said: 'Imagination is more important than knowledge'. Of course, he also said: 'If I had only known, I would have been a locksmith'.
Quote:Original post by random_thinker
#include <fstream>#include <sstream>#include <string>std::string fileToString(const std::string& filename){    std::ostringstream out;    std::ifstream in(filename.c_str());    out << in.rdbuf();    return out.str();   }std::string strbuf = fileToString("file.txt");


Then you can use the rather rich facilities of std::string to manipulate strbuf. I use the name 'strbuf' loosely here, as it is just a string. This is not to be confused with the standard library 'stringbuf' and 'wstringbuf' that are specializations of the 'basic_stringbuf<>' template class.

Better yet,
  #include <fstream>  #include <iterator>  #include <string>  // ...  string fileimage = string(istreambuf_iterator<char>(ifstream(filename.c_str())),                            istreambuf_iterator<char>());

Of course, this doesn't give you the opportunity to check for I/O errors, but it;s as simple as you can get for reading a file into an in-memory image.

Stephen M. Webb
Professional Free Software Developer

Quote:Original post by Bregma
Better yet,
  #include <fstream>  #include <iterator>  #include <string>  // ...  string fileimage = string(istreambuf_iterator<char>(ifstream(filename.c_str())),                            istreambuf_iterator<char>());



What beautifully elegant C++ code...fantastic!

--random
--random_thinkerAs Albert Einstein said: 'Imagination is more important than knowledge'. Of course, he also said: 'If I had only known, I would have been a locksmith'.
Quote:Original post by ToohrVyk
Quote:Original post by rip-off
Also, since getline uses the last as the delimiter, but you probably meant to use '3'. If not please specify what you want to do.


istream::getline(char*, streamsize) uses the last as the number of characters to be read.


Apologies, I must have been thinking of std::getline when I wrote that. [embarrass]

This topic is closed to new replies.

Advertisement