Getting Std :: Ifstream to Handle Lf, Cr, and Crlf

Getting std :: ifstream to handle LF, CR, and CRLF?

As Neil pointed out, "the C++ runtime should deal correctly with whatever the line ending convention is for your particular platform."

However, people do move text files between different platforms, so that is not good enough. Here is a function that handles all three line endings ("\r", "\n" and "\r\n"):

std::istream& safeGetline(std::istream& is, std::string& t)
{
t.clear();

// The characters in the stream are read one-by-one using a std::streambuf.
// That is faster than reading them one-by-one using the std::istream.
// Code that uses streambuf this way must be guarded by a sentry object.
// The sentry object performs various tasks,
// such as thread synchronization and updating the stream state.

std::istream::sentry se(is, true);
std::streambuf* sb = is.rdbuf();

for(;;) {
int c = sb->sbumpc();
switch (c) {
case '\n':
return is;
case '\r':
if(sb->sgetc() == '\n')
sb->sbumpc();
return is;
case std::streambuf::traits_type::eof():
// Also handle the case when the last line has no line ending
if(t.empty())
is.setstate(std::ios::eofbit);
return is;
default:
t += (char)c;
}
}
}

And here is a test program:

int main()
{
std::string path = ... // insert path to test file here

std::ifstream ifs(path.c_str());
if(!ifs) {
std::cout << "Failed to open the file." << std::endl;
return EXIT_FAILURE;
}

int n = 0;
std::string t;
while(!safeGetline(ifs, t).eof())
++n;
std::cout << "The file contains " << n << " lines." << std::endl;
return EXIT_SUCCESS;
}

Wrapping std::getline()

You should take the stream by reference because streams typically cannot be copied. Also the string should be passed by reference because you want to write to it.

To be generic you can use the same interface as std::getline does. As you want to use specific delimiters, they need not be passed as arguments. If you make the function a template then it will work with any stream that also works for std::getline:

#include <iostream>
#include <sstream>
#include <string>

template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& my_getline(
std::basic_istream<CharT,Traits>& input,
std::basic_string<CharT,Traits,Allocator>& str)
{
return std::getline(input,str);
}



int main() {
std::istringstream s{"hello world"};
std::string foo;
my_getline(s,foo);
std::cout << foo;
}

However at this point I'm stuck. From some searching, although getline returns a stream object (?) it also has an implicit cast-to-bool operator.

It's not getline that converts to bool but the stream returned by getline can be converted to bool. Your line is almost correct, but it needs to be a reference (and you need not spell out the type explicitly):

 auto& ret = std::getline(ifs, s);
// more code
return ret;

Note that I didn't address the actual issue of extracting characters until any of the delimiters is encountered (rather than only the platform specific newline that you already get with bare std::getline).

Running function with ifstream and stringstream multiple times

My suggestion:

std::string Qual(double *a)
{
std::string line;
char Qualities[] = {'1', '2', '3', '4' ,'5', '6', '7','8','\0'};
std::string Read_qual;

std::srand(std::time(nullptr));
std::random_device rd;
std::default_random_engine gen(rd());
std::discrete_distribution<> d({a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]);
Read_qual += Qualities[d(gen)];
return Read_qual;
}

and the main()

 int main()
{
std::ifstream infile("Freq.txt");
double alldata[150][8];
for (int i=0, i<150; i++)
for (int j=0; j<8; j++) infile >> alldata[i][j];
infile.close();

for (int idx = 0; idx < 2000; idx++)
{
for (int row = 0; row < 150; row++)
std::cout << Qual(alldata[row]) << std::endl;
}
return 0;
}

How to test if std::ifstream reached EOL

If I get to guess how you are currently reading it

No,

 ins >> stuff;

discards whitespace.

You want to do a

std::getline(ins, line_string);

And process it line by line.

Get each value from a string via std::ifstream

You must use an istringstream, not an ifstream.

Why result from std::getline() is not as expected

In v2, the values end with a carriage return (\r). When this is printed to the terminal, it makes the cursor go back to the beginning of the line, so the ))) is printed over top of the (((. The same thing happens when the temp values are displayed, because it displays the entire line.

Please also see Getting std :: ifstream to handle LF, CR, and CRLF? .



Related Topics



Leave a reply



Submit