stringstream::ignore(INT_MAX, '\n') causes stream to fail - c++

stringstream always seems to fail when I call stringstream::ignore(), even if this is done after calling stringstream::clear():
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cassert>
using namespace std;
int main() {
int a, b;
stringstream ss;
string str;
ifstream inFile("file.txt");
if(!inFile) {
cerr << "Fatal: Cannot open input file." << endl;
exit(1);
}
while(getline(inFile, str)) {
ss << str; // read string into ss
ss >> a >> b; // stream fails trying to store string into int
ss.clear(); // reset stream state
assert(ss.good()); // assertion succeeds
ss.ignore(INT_MAX, '\n'); // ignore content to next newline
assert(ss.good()); // assertion fails, why?
}
return 0;
}
file.txt contains the following text:
123 abc
456 def
Why is ss.good() false after ss.ignore()?

std::endl outputs \n and flushes the stream. However, stringstream::flush() is meaningless and does nothing. flush only has meaning when the underlying buffer is tied to an output device like the terminal, however, a stringstream has nowhere to flush the contents to. If you want to clear the contents of a stringstream do ss.str(""); instead. However, I would probably change the code to the following:
while(getline(inFile, str)) {
ss.str(str); // call ss.str() to assign a new string to the stringstream
if(!ss >> a >> b) // check if stream fails trying to store string into int
{
ss.clear(); // Read failed, so reset stream state
}
else
{
// Read successful
}
// Do other stuff
}
Also, if you want to insert a newline into the stringstream, just do ss << '\n'; and do not call std::endl.

It turns out there is no newline at the end of ss. After executing the following statements:
getline(infile, str);
ss << str;
ss will not contain a newline character, because getline() does not add a newline character to the end of the string stored into the second parameter. As a result, when this statement is executed:
ss.ignore(INT_MAX, '\n');
the stream fails because it reaches the end of the stream without finding a newline character to stop at.
ss.ignore() is not necessary if ss.str() is used to store the string, which replaces the entire contents of the stream. Should the stream fail, it should be reset and its contents set to the empty string "". Alternatively, ss.ignore() could be used, but only as long as a newline character is inserted into the stream immediately after the data is read so that it does not cause the stream to fail—but this would be redundant if the contents of the stream is later set to another value using ss.str().
A successful read of the next line of the file can be ensured by calling ss.clear() before the stream is assigned the contents of the next line of the file, since the old contents of the stream are overwritten on ss.str(). The stream state can be reset at the beginning of the loop, and no problems would occur even if the stream fails later in the loop:
while(getline(inFile, str)) {
ss.clear(); // make sure stream is good
ss.str(str); // overwrite contents of stream with str
ss >> a >> b;
// Even if the stream fails after this line, the stream is reset before each
// line is stored into the stream, and no problems should occur while reading
// and parsing subsequent lines in the file.
// Code to validate and store data from file...
}

Related

Why do I need clear() stringstream after reading from it in a function?

Why should I write ss.clear() in function Read() to be able to write to stringstream ss again?
#include <iostream>
#include <sstream>
using namespace std;
void Read(istream& ss, string& s)
{
while(getline(ss, s)){
cout << s << endl;
}
ss.clear();
}
int main()
{
stringstream ss;
string s;
ss << "A\nB\n";
Read(ss, s);
ss << "C\n";
Read(ss, s);
}
If ss.clear() is commented, the third line is not written to cout.
When you call
ss << "A\nB\n";
Read(ss, s);
The first call to getline extracts A, the second extracts B, and it is important to understand that you can only know that you are at the end of the stream after getline has been called once more. The third call to getline fails, there is no 3rd line in the stream, and the loop stops. From cppreference:
If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.
Once the failbit is set, the stream cant be used to extract more. Calling clear resets the error bits so you can continue using the stream.

using getline() while separating comma didn't work

I have read a CSV file that has line ending character as '\r', the reading operation done successfully, but the problem started when i pass the read line in to the while(getline(ss,arr2,',')) for separating comma..it does work properly for the first line but all the next iterations are empty(i.e)it has been failing to separate the comma in the string.
int main()
{
cout<<"Enter the file path :";
string filename;
cin>>filename;
ifstream file;
vector<string>arr;
string line,var;
stringstream content;
file.open(filename.c_str(),ios::in );
line.assign((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
string arr2;
stringstream ss;
content<<line;
//sqlite3 *db;int rc;sqlite3_stmt * stmt;
int i=0;
while (getline(content,var,'\r'))
{
ss.str(var);//for each read the ss contains single line which i could print it out.
cout<<ss.str()<<endl;
while(getline(ss,arr2,','))//here the first line is neatly separated and pushed into vector but it fail to separate second and further lines i was really puzzled about this behaviour.
{
arr.push_back(arr2);
}
ss.str("");
var="";
arr2="";
for(int i=0;i<arr.size();i++)
{
cout<<arr[i]<<endl;
}
arr.clear();
}
getch();
}
what went wrong in the above...I see nothing right now:(
The stringstream::str method does not reset / clear the internal state of the stream. After the first line, the internal state of ss is EOF (ss.eof() returns true).
Either use a local variable inside the while loop:
while (getline(content,var,'\r'))
{
stringstream ss(var);
Or clear the stream before ss.str:
ss.clear();
ss.str(var);

Streaming I/O in c++

I am trying to get this file stream program to work but when I run it all that happens is it outputs "Writing" instead of outputting the file. What am i doing wrong?
#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char str[10];
ifstream b_file ( "ioTest.txt" );
b_file>> str;
cout<< str <<"\n";
cin.get();
}
The standard input streams use whitespace as a delimiter for input. If you try extracting to a string, it will extract every character until a whitespace character is found. If you need the entire content of the file, here are a few options:
while (in >> word)
while (b_file >> word)
{
std::cout << word;
}
This method will iterate over each whitespace-separated tokens in the input stream.
std::getline()
while (std::getline(b_file, line))
{
std::cout << line;
}
std::getline() retrieves line-wise input, meaning it will extract every character until it reaches a delimiter. The delimiter by default is the newline but it can be specified as a third argument.
std::istream_iterator<T>
std::copy(std::istream_iterator<std::string>(b_file),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
std::istream_iterator is a special-purpose stream iterator class designed to "iterate" over tokens of type T from an input stream.
rdbuf()
std::cout << b_file.rdbuf();
This is more low-level. An overload of std::ostream::operator<<() takes a stream buffer pointer as an argument, and it will extract characters directly from the buffer.

Using C++ ifstream extraction operator>> to read formatted data from a file

As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.

How do I read a text file from the second line using fstream?

How can I make my std::fstream object start reading a text file from the second line?
Use getline() to read the first line, then begin reading the rest of the stream.
ifstream stream("filename.txt");
string dummyLine;
getline(stream, dummyLine);
// Begin reading your stream here
while (stream)
...
(Changed to std::getline (thanks dalle.myopenid.com))
You could use the ignore feature of the stream:
ifstream stream("filename.txt");
// Get and drop a line
stream.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
// Get and store a line for processing.
// std::getline() has a third parameter the defaults to '\n' as the line
// delimiter.
std::string line;
std::getline(stream,line);
std::string word;
stream >> word; // Reads one space separated word from the stream.
A common mistake for reading a file:
while( someStream.good() ) // !someStream.eof()
{
getline( someStream, line );
cout << line << endl;
}
This fails because: When reading the last line it does not read the EOF marker. So the stream is still good, but there is no more data left in the stream to read. So the loop is re-entered. std::getline() then attempts to read another line from someStream and fails, but still write a line to std::cout.
Simple solution:
while( someStream ) // Same as someStream.good()
{
getline( someStream, line );
if (someStream) // streams when used in a boolean context are converted to a type that is usable in that context. If the stream is in a good state the object returned can be used as true
{
// Only write to cout if the getline did not fail.
cout << line << endl;
}
}
Correct Solution:
while(getline( someStream, line ))
{
// Loop only entered if reading a line from somestream is OK.
// Note: getline() returns a stream reference. This is automatically cast
// to boolean for the test. streams have a cast to bool operator that checks
// good()
cout << line << endl;
}
The more efficient way is ignoring strings with std::istream::ignore
for (int currLineNumber = 0; currLineNumber < startLineNumber; ++currLineNumber){
if (addressesFile.ignore(numeric_limits<streamsize>::max(), addressesFile.widen('\n'))){
//just skipping the line
} else
return HandleReadingLineError(addressesFile, currLineNumber);
}
HandleReadingLineError is not standart but hand-made, of course.
The first parameter is maximum number of characters to extract. If this is exactly numeric_limits::max(), there is no limit:
Link at cplusplus.com: std::istream::ignore
If you are going to skip a lot of lines you definitely should use it instead of getline: when i needed to skip 100000 lines in my file it took about a second in opposite to 22 seconds with getline.
Call getline() once to throw away the first line
There are other methods, but the problem is this, you don't know how long the first line will be do you? So you can't skip it till you know where that first '\n' is. If however you did know how long the first line was going to be, you could simply seek past it, then begin reading, this would be faster.
So to do it the first way would look something like:
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
// Open your file
ifstream someStream( "textFile.txt" );
// Set up a place to store our data read from the file
string line;
// Read and throw away the first line simply by doing
// nothing with it and reading again
getline( someStream, line );
// Now begin your useful code
while( !someStream.eof() ) {
// This will just over write the first line read
getline( someStream, line );
cout << line << endl;
}
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string textString;
string anotherString;
ifstream textFile;
textFile.open("TextFile.txt");
if (textFile.is_open()) {
while (getline(textFile, textString)){
anotherString = anotherString + textString;
}
}
std::cout << anotherString;
textFile.close();
return 0;
}
this code can read file from your specified line from file but you have to make file in file explorer before hand my file name is "temp" code is given below
https://i.stack.imgur.com/OTrsj.png
hope this can help
You can use ignore function as follow:
fstream dataFile("file.txt");
dataFile.ignore(1, '\n'); // ignore one line
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char buffer[256];
ifstream myfile ("test.txt");
// first line
myfile.getline (buffer,100);
// the rest
while (! myfile.eof() )
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
return 0;
}