ifstream eof function (C++) - c++

I have this code:
string a = "D:\\Users\\user-pc\\Desktop\\testing\\a.txt";
ifstream f;
/*edit*/ string line;
/*edit*/ getline(f, line);
f.open(a);
if ( f.eof() )
cout << "ended";
else
cout << "nope"
and the file 'a.txt' which has nothing in it.
the output is nope, alway nope. I don't get it.. Do I use it wrong?
EDIT: still .eof() not working

std::basic_istream<...>::eof() only returns true if a recent extraction set the appropriate bit in the stream state. When a file stream is constructed, its stream state is always that of std::ios_base::goodbit.
An alternative is to check if the next available character is the EOF character:
if (f.peek() == std::char_traits<char>::eof())

eofbit error state flag is only set once a read tries to read past the end of the file.

Related

Why istringstream appends '-1' character at the end of stream?

I've noticed that when I'm using istringstream eof() doesn't return true even if the whole string is "consumed". For example:
char ch;
istringstream ss{ "0" };
ss >> ch;
cout << ss.peek() << " " << (ss.eof() ? "true" : "false");
Outputs(VS2015):
-1 false
eof() isn't supposed to return true when all the data is consumed. It's supposed to return true when you attempt to read more data than is available.
In this example, you never do that.
In particular, peek is a "request", that won't set EOF even when there's nothing left to read; because you're, well, peeking. However, it will return the value of the macro EOF (commonly -1), which is what you're seeing when you output peek()'s result. Nothing is "appended" to the stream.
Read the documentation for functions that you use.
std::istream::peek
Peek next character Returns the next character in the input sequence,
without extracting it: The character is left as the next character to
be extracted from the stream.
If any internal state flags is already set before the call or is set
during the call, the function returns the end-of-file value (EOF).
http://www.cplusplus.com/reference/istream/istream/peek/

C++ Read in file with only numbers (doubles)

I'm trying to read in a file that should contain only numbers in it. I can successfully read in the entire file if it meets that criteria, but if it so happened to have a letter in it, I need to return false with an error statement.
The problem is I'm finding it hard for my program to error when it finds this character. It can find it no problem, but when it does, it decides to just skip over it.
My code to read in the file and attempt to read in only numbers:
bool compute::Read (ifstream& stream)
{
double value;
string line;
int lineNumber = 1;
if (stream)
{
while (getline(stream, line))
{
lineNumber++;
istringstream strStream(line);
while (strStream >> value)
{
cout << value << endl;
}
}
}
return true;
}
The input file which I use for this is
70.5 61.2 A8 10.2
2
Notice that there is a non-number character in my input file. It should fail and return false at that point.
Currently, all it does is once it hits the "A", it simply returns to the next line, continuing the getline while loop.
Any help with this would be much appreciated.
The stringstream does catch those errors, but you're doing nothing to stop the enclosing loop from continuing when an error is found. You need to tailor your main loop so that it stops when the stringstream finds an error, which you can't do if the stringstream is being reconstructed on each iteration. You should create a for() loop instead and construct the stringstream in the declaration part. And the condition to the loop should be "as long as the stringstream and stream do not catch an error". For example:
for (std::istringstream iss; iss && std::getline(stream, line);)
{
iss.clear();
iss.str(line);
while (iss >> value)
{
std::cout << value << '\n';
}
}
Futhermore, it doesn't look like you need to use std::getline() or std::istringstream if you just want to print each value. Just do:
while (stream >> value) {
std::cout << value << '\n';
}
The above will stop when it finds an invalid character for a double.
You need the code to stop streaming but return false if it hasn't yet reached the end of the "input".
One way, possibly not the most efficient but still one way, to do that is parse a word at a time.
If you read first into a std::string and if it works (so the string is not empty) create an istringstream from that string, or reuse an existing one, and try streaming that into a double value.
If that fails, you have an invalid character.
Of course you can read a line at a time from the file, then split that into words, so that you can output a meaningful error message showing what line the bad text was found.
The issue of reading straight into doubles is that the stream will fail when it reaches end of file.
However it is possible to workaround that too because the reason for failing has an error status which you can check, i.e. you can check if it eofbit is set. Although the f in eofbit stands for "file" it applies to any stream not just files.
Although this method may sound better than reading words into a string first, I prefer that method in normal circumstances because you want to be able to report the error so you'll want to print in the error what was read.

How do I know if the specified file has been read correctly?

Why does ifstream set the failbit to 1 after reading the last line of the specified file? How do I know if the specified file has been read correctly?
bool read_csv_file(const char* filename, vector<string>& lines, bool adding = false)
{
if( !adding ) lines.clear();
ifstream csvfile;
csvfile.open(filename);
if( csvfile.is_open() )
{
string line;
while( csvfile.good() && getline(csvfile,line) )
{
lines.push_back(line);
cout << "fail: " << csvfile.fail() << endl;
}
cout << "fail: " << csvfile.fail() << endl;
csvfile.close();
return (!csvfile.fail());
}
return false;
}
The fail bit is set after you run off the end of the file. Once that happens, you mustn't attempt to interpret the result of your input operation. That's perfectly fine, though, and getline will not set the fail bit while there's still any data to be read. So the following standard loop extracts all the lines:
for (std::string line; std::getline(csvfile, line); )
{
// process "line"
}
// all done
The only reason failbit could be set after reading the last
line (or any line) is if there were an error in the library, and
I don't really believe it. If failbit is set, it means that
you didn't read anything. In your case, it will never be set
when you're in the loop; if it were set, getline would have
evaluated to false, and you wouldn't have entered the loop.
And of course, the loop terminates precisely because getline
fails (or would fail—normally, you would not test for
good before doing input, and if you do, consider that the
failbit was set, regardless, if the test fails).
The usual pattern for this sort of thing is:
while ( someInput ) {
// ...
}
if ( csvfile.bad() ) {
// Serious error (disk read error, etc.)...
} else if ( ! csvfile.eof() ) {
// Formatting error...
} else {
// Normal end of file...
}
When someInput is std::getline(), however, you will never
fail because of a formatting error, so the else if above will
never be true (and a lot of code treats hard disk errors as if
they were an end of file, and so ignores the if part as well).
Too check for erroneous reads, you must test badbit using stream.bad().
Failbit indicates failure in operation logic, and apparently getline sets it when reaching EOF (confirmed on my machine).

Reading from ifstream won't read whitespace

I'm implementing a custom lexer in C++ and when attempting to read in whitespace, the ifstream won't read it out. I'm reading character by character using >>, and all the whitespace is gone. Is there any way to make the ifstream keep all the whitespace and read it out to me? I know that when reading whole strings, the read will stop at whitespace, but I was hoping that by reading character by character, I would avoid this behaviour.
Attempted: .get(), recommended by many answers, but it has the same effect as std::noskipws, that is, I get all the spaces now, but not the new-line character that I need to lex some constructs.
Here's the offending code (extended comments truncated)
while(input >> current) {
always_next_struct val = always_next_struct(next);
if (current == L' ' || current == L'\n' || current == L'\t' || current == L'\r') {
continue;
}
if (current == L'/') {
input >> current;
if (current == L'/') {
// explicitly empty while loop
while(input.get(current) && current != L'\n');
continue;
}
I'm breaking on the while line and looking at every value of current as it comes in, and \r or \n are definitely not among them- the input just skips to the next line in the input file.
There is a manipulator to disable the whitespace skipping behavior:
stream >> std::noskipws;
The operator>> eats whitespace (space, tab, newline). Use yourstream.get() to read each character.
Edit:
Beware: Platforms (Windows, Un*x, Mac) differ in coding of newline. It can be '\n', '\r' or both. It also depends on how you open the file stream (text or binary).
Edit (analyzing code):
After
while(input.get(current) && current != L'\n');
continue;
there will be an \n in current, if not end of file is reached. After that you continue with the outmost while loop. There the first character on the next line is read into current. Is that not what you wanted?
I tried to reproduce your problem (using char and cin instead of wchar_t and wifstream):
//: get.cpp : compile, then run: get < get.cpp
#include <iostream>
int main()
{
char c;
while (std::cin.get(c))
{
if (c == '/')
{
char last = c;
if (std::cin.get(c) && c == '/')
{
// std::cout << "Read to EOL\n";
while(std::cin.get(c) && c != '\n'); // this comment will be skipped
// std::cout << "go to next line\n";
std::cin.putback(c);
continue;
}
else { std::cin.putback(c); c = last; }
}
std::cout << c;
}
return 0;
}
This program, applied to itself, eliminates all C++ line comments in its output. The inner while loop doesn't eat up all text to the end of file. Please note the putback(c) statement. Without that the newline would not appear.
If it doesn't work the same for wifstream, it would be very strange except for one reason: when the opened text file is not saved as 16bit char and the \n char ends up in the wrong byte...
You could open the stream in binary mode:
std::wifstream stream(filename, std::ios::binary);
You'll lose any formatting operations provided my the stream if you do this.
The other option is to read the entire stream into a string and then process the string:
std::wostringstream ss;
ss << filestream.rdbuf();
OF course, getting the string from the ostringstream rquires an additional copy of the string, so you could consider changing this at some point to use a custom stream if you feel adventurous.
EDIT: someone else mention istreambuf_iterator, which is probably a better way of doing it than reading the whole stream into a string.
Wrap the stream (or its buffer, specifically) in a std::streambuf_iterator? That should ignore all formatting, and also give you a nice iterator interface.
Alternatively, a much more efficient, and fool-proof, approach might to just use the Win32 API (or Boost) to memory-map the file. Then you can traverse it using plain pointers, and you're guaranteed that nothing will be skipped or converted by the runtime.
You could just Wrap the stream in a std::streambuf_iterator to get data with all whitespaces and newlines like this .
/*Open the stream in default mode.*/
std::ifstream myfile("myfile.txt");
if(myfile.good()) {
/*Read data using streambuffer iterators.*/
vector<char> buf((std::istreambuf_iterator<char>(myfile)), (std::istreambuf_iterator<char>()));
/*str_buf holds all the data including whitespaces and newline .*/
string str_buf(buf.begin(),buf.end());
myfile.close();
}
By default, this skipws flag is already set on the ifstream object, so we must disable it. The ifstream object has these default flags because of std::basic_ios::init, called on every new ios_base object (more details). Any of the following would work:
in_stream.unsetf(std::ios_base::skipws);
in_stream >> std::noskipws; // Using the extraction operator, same as below
std::noskipws(in_stream); // Explicitly calling noskipws instead of using operator>>
Other flags are listed on cpp reference.
The stream extractors behave the same and skip whitespace.
If you want to read every byte, you can use the unformatted input functions, like stream.get(c).
Why not simply use getline ?
You will get all the whitespaces, and while you won't get the end of lines characters, you will still know where they lie :)
Just Use getline.
while (getline(input,current))
{
cout<<current<<"\n";
}
I ended up just cracking open the Windows API and using it to read the whole file into a buffer first, and then reading that buffer character by character. Thanks guys.

C++ reading from a file blocks any further writing. Why?

I am implementing a very simple file database. I have 2 basic operations:
void Insert(const std::string & i_record)
{
//create or append to the file
m_fileStream.open(m_fileName.c_str(), std::ios::out | std::ios::app);
if (m_fileStream.is_open())
{
m_fileStream << i_record << "\n";
}
m_fileStream.flush();
m_fileStream.close();
}
/*
* Returns a list with all the items in the file.
*/
std::vector<std::string> SelectAll()
{
std::vector<std::string> results;
m_fileStream.open(m_fileName.c_str(), std::ios::in);
std::string line;
if (m_fileStream.is_open())
{
while (!m_fileStream.eof())
{
getline (m_fileStream, line);
results.push_back(line);
}
}
m_fileStream.close();
return results;
}
the class has m_fileStream and m_fileName as private members.
OK - here's the problem:
If I do something like:
db->Insert("a");
db->SelectAll();
db->Insert("b");
The end result is that the file will contain only "a"; WHY?
NOTE: it seems that getline() will set the fail bit. but why?
Change
while (!m_fileStream.eof())
{
getline (m_fileStream, line);
results.push_back(line);
}
to
while (getline (m_fileStream, line))
{
results.push_back(line);
}
Otherwise you will get one additional empty line at the end. eof() will return true only once you tried to read past the end of the file, and not if only the next read would be past the end of the file.
It sets the failbit because getline tries to extract characters from the stream. If there are no characters left (and no '\n' has been seen yet), stream.get(c) to a character will set the failbit. Then getline will set the eofbit and then .eof() will return true, and your loop exits.
If you don't want failbit set, then change your condition from !stream.eof() to stream.peek() != EOF (and make sure there is a trailing newline in your file).
This now is also the solution to your problem: .close() doesn't .clear() your stream, so the failbit still is set if you reopen your file. call stream.clear() after reading your stuff in, and then it works.
I think litb pretty much nailed it. But just to add my $0.02:
1) I always favored:
while ( stream && (stream.peek() != EOF) ) {...}
As [bad] events other than EOF can occur.
(And, as mentioned by litb, peek()!=EOF gets around the problem of stream not setting EOF until we try to read past the end.)
.
2) Since "m_fileStream" is open'ed, read/written/flushed, and closed in both these methods...
Why not declare it locally on the stack? Doing so assures that no previous state issues remain behind to mess you up. And yer accessing the disk, so efficiency may not be the largest concern...
Besides, you can be lazy:
ifstream stream ( m_fileName.c_str() );
ASSERT( stream, !=, NULL ); // Uses my own ASSERT macro && stream.operator().
while ( stream && (stream.peek() != EOF) ) {...}