I've looked up several instances in EOF, but in all instances EOF is being used on a file that is part of the program, for example:
std::fstream myFile("file.txt", std::ios::in);
while(!myFile.eof()) {
/*program*/
}
However in this instance, I'm not using a file as part of the code. I'm just using basic cin commands. There's a command to quit, but let's say a user runs the program like this:
./program <myFile.txt> myOutput
Let's say that myFile had these commands in this:
add 1
add 2
delete 1
print
That's all fine, but they forgot to add a quit command at the end, so the code won't stop. So how do I get the code to detect EOF in this situation and stop?
The correct way to detect end-of-file is to check each input operation for success.
For example, with getline you'd use
std::string line;
while (std::getline(std::cin, line)) {
// do stuff with line
}
Or with >>:
while (std::cin >> x) {
// do stuff with x
}
This applies to all input streams, whether they're from files (fstream) or e.g. cin.
End of file (EOF) means there is nothing more to read from the file buffer, it’s not something one puts explicitly at the file itself.. you should still get there fine with your code
Another way is to read the buffer until there are no more bytes to read there
Related
So i've read all the lines from a file thusly
while (getline(ifile,line))
{
// logic
}
Where ifile is an ifstream and line is a string
My problem is I now want to use getline over again, and seem to be unable to return to the beginning of the file, as running
cout << getline(ifile,line);
Will return 0
I've attempted to use:
ifile.seekg (0, ios::beg);
To no avail, it seems to have no effect. How do I go back to the start of the file?
Since you have reached (and attempted to read past) the end of the file, the eof and fail flags will be set. You need to clear them using ifile.clear – then try seeking:
ifile.clear();
ifile.seekg(0);
This is because the eof flag has been set on the stream - due to you reaching the end of the file. so you have to clear this as an additional step.
Eg
ifile.clear();
ifile.seekg (0, ios::beg);
FYI: In my case, the order DID matter, thus
clear
seek
otherwise the next getline operation failed (MSVC v120)
I want to read in one file line-by-line and output each line I read to a new file. In this code, cin has been redirected to refer to the input file, and cout has been redirected to refer to the output file.
The loop successfully writes every line in the file, but then it gets stuck on the final getline call. As a result, "Done" is not written to the file and the program does not terminate.
#include <string>
#include <iostream>
using namespace std;
int main() {
string line;
while(getline(cin, line)) {
cout << line << endl;
}
cout << "Done";
return 0;
}
Strangely, if I forcibly terminate the program, it seems to suddenly execute as desired, with "Done" being written.
Can someone point me in the right direction? Is there a flaw in the code, or is this some external configuration issue?
Notes: The input file in question ends with a newline character. Also, I do not want to use any includes besides these two.
The code should terminate on end of file (EOF) or any sort of file error. (The getline being called is:
http://en.cppreference.com/w/cpp/string/basic_string/getline
It returns the cin istream and then invokes its boolean conversion operator:
http://www.cplusplus.com/reference/ios/ios/operator_bool/
that checks if badbit or failbit is set on the stream. The failbit state should be set when a read is attempted with the stream already at EOF, or if there is an error.)
Per the comments above, it seems like this does work when the code is run from the shell directly. My guess is Eclipse is doing something complicated where it either intentionally sends the file into the program and then switches to an interactive input mode, or has a bug in which it doesn't close its end of a pipe or pty/tty it is using to send input to the program. (I.e. Eclipse is not binding stdin directly to the file itself in running the program.)
If one wanted to debug it further, one could look at the process state using tools like lsof. (Assuming a UNIXy system.) Might also be worth raising the issue in an Eclipse forum. The IDE is not my area of expertise.
I am using the standard C++ fstreams library and I am wondering what is the right way to use it. By experience I sort of figured out a small usage protocol, but I am not really sure about it. For the sake of simplicity let's assume that I just want to read a file, e.g., to filter its content and put it on another file. My routine is roughly as follows:
I declare a local istream i("filename") variable to open the file;
I check either i.good() or i.is_open() to handle the case where something went bad when opening, e.g., because the file does not exist; after, I assume that the file exists and that i is ok;
I call i.peek() and then again i.good() or i.eof() to rule out the case where the file is empty; after, I assume that I have actually something to read;
I use >> or whatever to read the file's content, and eof() to check that I am over;
I do not explicitly close the file - I rely on RAII and keep my methods as short and coherent as I can.
Is it a sane (correct, minimal) routine? In the negative case, how would you fix it? Please note that I am not considering races - synchronization is a different affair.
I would eliminate the peek/good/eof (your third step). Simply attempt to read your data, and check whether the attempted read succeeded or failed. Likewise, in the fourth step, just check whether your attempted read succeeded or not.
Typical code would be something like:
std::ifstream i("whatever");
if (!i)
error("opening file");
while (i >> your_data)
process(your_data);
if (!i.eof())
// reading failed before end of file
It's simpler than you have described. The first two steps are fine (but the second is not necessary if you follow the rest of my advice). Then you should attempt extraction, but use the extraction as the condition of a loop or if statement. If, for example, the file is formatted as a series of lines (or other delimited sequences) all of the same format, you could do:
std::string line;
while (std::getline(i, line)) {
// Parse line
}
The body of the loop will only execute if the line extraction works. Of course, you will need to check the validity of the line inside the loop.
If you have a certain series of extractions or other operations to do on the stream, you can place them in an if condition like so:
if (i >> some_string &&
i.get() == '-' &&
i >> some_int) {
// Use some_string and some_int
}
If this first extraction fails, the i.ignore() not execute due to short-circuit evaluation of &&. The body of the if statement will only execute if both extractions succeed. If you have two extractions together, you can of course chain them:
if (i >> some_string >> some_int) {
// Use some_string and some_int
}
The second extraction in the chain will not occur if the first one fails. A failed extraction puts the stream in a state in which all following extractions also fail automatically.
For this reason, it's also fine to place the stream operations outside of the if condition and then check the state of the stream:
i >> some_string >> some_int;
if (i) {
// Use some_string and some_int
}
With both of these methods, you don't have to check for certain problems with the stream. Checking the stream for eof() doesn't necessarily mean that the next read will fail. A common case is when people use the following incorrect extraction loop:
// DO NOT DO THIS
while (!i.eof()) {
std::getline(i, line)
// Do something with line
}
Most text files end with an extra new line at the end that text editors hide from you. When you're reading lines from the text file, for the last iteration you haven't yet hit the end of file because there's still a \n to read. So the loop continues, attempts to extract the next line which doesn't exist and screws up. People often observe this as "reading the last line of the file twice".
I have this code in an Objective-C class (in an Objective-C++ file):
+(NSString *)readString
{
string res;
std::getline(cin, res);
return [NSString stringWithCString:res.c_str() encoding:NSASCIIStringEncoding];
}
When I run it, I get a zero-length string, Every time. Never given the chance to type at the command line. Nothing. When I copy this code verbatim into main(), it works. I have ARC on under Build Settings. I have no clue what it going on. OSX 10.7.4, Xcode 4.3.2.
It is a console application.
It means there is input waiting to be read on the input. You can empty the input:
cin.ignore(std::numeric_limits<std::streamsize>::max();
std::getline(cin, res);
If this is happening it means you did not read all the data off the input stream in a previous read. The above code will trash any user input before trying to read more.
This probably means that you are mixing operator>> with std::getline() for reading user input. You should probably pick one technique and use that (std::getline()) throughout your application ( you can mix them you just have to be more careful and remove the '\n' after using operator>> to make sure any subsequent std::getline() is not confused..
If you want to read a number read the line then parse the number out of the line:
std::getline(cin, line);
std::stringstream linestream(line);
linestream >> value;
You can simply do:
cin.ignore();
or use
cin.clear();
cin.sync();
before using getline()
How do I get the filename from redirection from the shell in my C++ code? i.e. ./MyProgram < myfile , I want to get myfile as the filename and its content line by line.
**Edit: I managed to get the input from file. Thanks for the help. However, after the looping through the file content, I want to keep user input with cin. It's like this:
while (true)
{
if (cin.eof() == false)
{
getline(cin, line);
cout << line;
}else{
cin >> choice;
}
}
You can't (at least not portably). This information is not provided to the program. Instead, you can access the data from myfile (in your example) by reading from standard input. E.g., you can use C++'s getline with cin as the first parameter.
Depending on the shell, you may have inherited a descriptor representing an actual file or a pipe. If it's an actual pipe (i.e. fifo), the name won't mean much. But you can get the name on linux (and on Windows, but it doesn't sound like you're interested in that).
See Getting Filename from file descriptor in C