1

I am looking to find a C++ fstream equivalent function of C fgets. I tried with get function of fstream but did not get what I wanted. The get function does not extract the delim character whereas the fgets function used to extract it. So, I wrote a code to insert this delim character from my code itself. But it is giving strange behaviour. Please see my sample code below;

#include <stdio.h>
#include <fstream>
#include <iostream>

int main(int argc, char **argv)
{
    char str[256];
    int len = 10;
    std::cout << "Using C fgets function" << std::endl;
    FILE * file = fopen("C:\\cpp\\write.txt", "r");
    if(file == NULL){
      std::cout << " Error opening file" << std::endl;
    }
    int count = 0;
    while(!feof(file)){
        char *result = fgets(str, len, file);
        std::cout << result << std::endl ;
        count++;
    }
    std::cout << "\nCount = " << count << std::endl;
    fclose(file);


std::fstream fp("C:\\cpp\\write.txt", std::ios_base::in);
int iter_count = 0; 
 while(!fp.eof() && iter_count < 10){

    fp.get(str, len,'\n');
    int count = fp.gcount();
    std::cout << "\nCurrent Count = " << count << std::endl;
    if(count == 0){
        //only new line character encountered
        //adding newline character
        str[1] = '\0';
        str[0] = '\n';
        fp.ignore(1, '\n');
        //std::cout << fp.get(); //ignore new line character from stream
    }
    else if(count != (len -1) ){

         //adding newline character
        str[count + 1] = '\0';
        str[count ] = '\n';
        //std::cout << fp.get(); //ignore new line character from stream
        fp.ignore(1, '\n');
        //std::cout << "Adding new line \n";
    }       

    std::cout << str  << std::endl;
    std::cout << " Stream State : Good: " << fp.good() << " Fail: " << fp.fail() << std::endl;

    iter_count++;
}
std::cout << "\nCount = " << iter_count <<  std::endl;
fp.close();


return 0;

}

The txt file that I am using is write.txt with following content:

This is a new lines.
Now writing second
line
DONE

If you observe my program, I am using fgets function first and then using the get function on same file. In case of get function, the stream state goes bad.

Can anyone please point me out what is going wrong here?

UPDATED: I am now posting a simplest code which does not work at my end. If I dont care about the delim character for now and just read the entire file 10 characters at a time using getline:

void read_file_getline_no_insert(){
    char str[256];
    int len =10;
    std::cout << "\nREAD_GETLINE_NO_INSERT FUNCITON\n" << std::endl;
    std::fstream fp("C:\\cpp\\write.txt", std::ios_base::in);
    int iter_count = 0; 
     while(!fp.eof() && iter_count < 10){

        fp.getline(str, len,'\n');
        int count = fp.gcount();
        std::cout << "\nCurrent Count = " << count << std::endl;
        std::cout << str  << std::endl;
        std::cout << " Stream State : Good: " << fp.good() << " Fail: " << fp.fail() << std::endl;   
        iter_count++;
    }
    std::cout << "\nCount = " << iter_count <<  std::endl;
    fp.close();

}
int main(int argc, char **argv)
{

    read_file_getline_no_insert();  

    return 0;
}

If wee see the output of above code:

READ_GETLINE_NO_INSERT FUNCITON

Current Count = 9
This is a
 Stream State : Good: 0 Fail: 1

Current Count = 0

 Stream State : Good: 0 Fail: 1

You would see that the state of stream goes Bad and the fail bit is set. I am unable to understand this behavior.

Rgds Sapan

Sapan
  • 1,593
  • 3
  • 24
  • 34
  • 4
    You are likely looking for [`getline`](http://en.cppreference.com/w/cpp/string/basic_string/getline) – Igor Tandetnik Mar 07 '15 at 04:33
  • There is also [`getline`](http://en.cppreference.com/w/cpp/io/basic_istream/getline) which is a more literal analog of `fgets`, but you probably want the one mentioned in the above comment, since working with `string`s is usually better than working with `char` arrays. –  Mar 07 '15 at 04:43
  • @IgorTandetnik: The question is quite clear that the delimiter character is to be kept, and `getline` does not do so. – Ben Voigt Mar 07 '15 at 04:46
  • @BenVoigt No, the question is quite clearly about exactly the opposite. "looking to find equivalent of fgets... fgets extract[s the delimiter] ... get function does not" – Igor Tandetnik Mar 07 '15 at 04:51
  • I posit the question is not clear. :P (it also seems to be an odd mix of "I want something that does X" and "please debug my code". OP would probably be better off asking one or the other rather than both) –  Mar 07 '15 at 04:52
  • @IgorTandetnik: Yes, "extract" means "read from the stream". `fgets` does that, and transfers it to the buffer. `getline` extracts but discards the delimiter. Since Sapan is concerned about the difference, we can conclude he wants the "transfer" behavior. So a solution should not leave the delimiter in the stream, but he does want it added to the received string, not discarded. – Ben Voigt Mar 07 '15 at 04:55
  • @BenVoigt Something like this then? `getline(mystream, mystring); if (!mystream.eof()) mystring.push_back('\n');` I mean, there's very little doubt as to exactly what character was extracted and discarded by `getline`. – Igor Tandetnik Mar 07 '15 at 04:59
  • @IgorTandetnik: Yes, with the default settings the delimiter is known. – Ben Voigt Mar 07 '15 at 05:01
  • 1
    @BenVoigt With the non-default settings the delimiter is also known - you've just passed it in. – Igor Tandetnik Mar 07 '15 at 05:02
  • @IgorTandetnik: The problem with iostreams is that everything is customizable. Including what it means for an extracted character to be "equal" to the delimiter. – Ben Voigt Mar 07 '15 at 05:06
  • Thanks for the comments. Unfortunately in my case, neither get nor getline function works. When using getline, After reading first line, it gets stuck and gcount always return 0. With get function also, after reading few lines, it gets stuck and very soon we can see stream state becoming BAD. – Sapan Mar 07 '15 at 06:17
  • @BenVoigt : Please see the updated code in my Post. This code right now is not concerned with the delimiting character being kept or thrown out. But when reading the characters in second iteration, the state of the stream becomes BAD and fail bit is set. Can anyone point out what is missing at my end.? – Sapan Mar 07 '15 at 06:39
  • [`while( !feof( file ) )` is always wrong](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong) – The Paramagnetic Croissant Mar 07 '15 at 06:44
  • The issue comes when say, a line in file has more characters than what I am trying to read. e.g. line has 25 characters and I read only 10 at a time. So, when I go for reading next time, it is not able to do that and fail bit is set. – Sapan Mar 07 '15 at 06:49
  • Re your update. istream's getline() function sets the stream to failbit if the buffer is exhausted before the delimiter is encountered. So, reading a line of 25 characters with a buffer of 10 will do that. So try reading the documentation for the functions you use. – Rob Mar 07 '15 at 06:50
  • @Rob, I agree with the fail bit explanation but still when we read the next set of 10 characters, it should print the next 10 characters but with the code above, it gets stuck and every further invocation to getline gives gcount() as 0. – Sapan Mar 07 '15 at 14:19
  • Ok after every read using getline(), I had to clear the flags using function clear() before going to read the next set of characters. I will now see how to handle the newline character which I want to be included in the string – Sapan Mar 07 '15 at 15:00

1 Answers1

9

std::getline() will read a string from a stream, until it encounters a delimiter (newline by default).

Unlike fgets(), std::getline() discards the delimiter. But, also unlike fgets(), it will read the whole line (available memory permitting) since it works with a std::string rather than a char *. That makes it somewhat easier to use in practice.

All types derived from std::istream (which is the base class for all input streams) also have a member function called getline() which works a little more like fgets() - accepting a char * and a buffer size. It still discards the delimiter though.

The C++-specific options are overloaded functions (i.e. available in more than one version) so you need to read documentation to decide which one is appropriate to your needs.

Rob
  • 1,966
  • 9
  • 13