This seems rather strange. I have a snippet of code that is as follows:
List(const char* fn) {
std::ifstream file(fn);
if (!file){
throw std::string("*** Failed to open file ") + std::string(fn) + std::string(" ***");
}
while (file) {
T e;
if (e.load(file)){
list.push_back(*new T(e));
}
}
}
With other people, it seems to run through the whole file just fine. But for me, I'm stuck in an infinite loop on my machine.
OS X - g++ 4.2
I have no clue as to why there is a difference of function here.
Here is the infinite loop:
while (file) {
T e;
if (e.load(file)){
list.push_back(*new T(e));
}
}
while(file) will return true as long as the file is left in a valid state.
You haven't told us what a T is or what its load method does, so we can't really give you much more info than that. You need to make sure that the load method either closes the file descriptor, or leaves it in eof state or something else like that.
Related
As far as I know, stream.ignore(n, 'n') should ignore an (n) amount of characters or if ‘\n’ is reached, and skip over to the next line, however, when I run the next code:
// include...
void insertInfo(int info) {
std::fstream stream("infoFile.txt"); // Open the file
while (!stream.eof()) {
std::string a{};
// getline(stream, a); <--- Tried this, didn't work either
stream.ignore(99, '\n');
} // Skip to the last line without any number, in theory
std::cout << info << std::endl; // Check if the output it's correct (Which is)
stream << info; // Insert the info
stream.close(); // Close the file
}
void main() //Main
{
std::cout << "Enter your name, followed by the info you want to add to infoFile:" << std::endl;
std::string info, temp = "";
std::getline(std::cin, temp); // Get the info input
std::stringstream sstream;
sstream << temp;
sstream >> temp >> info; // Remove the name keeping only the info
temp = ""; // ^
std::string::size_type sz;
insertInfo(stoi(info, &sz)); // Convert info string into an integer and insert it in infoFile
}
The console prints out the "info" correct value, however, when I check info.txt, in which I previously wrote a '0' on, you don't see any change.
I tried removing the "ignore" function and it overwrites the 0, which is exactly what I was trying to prevent.
I also tried using "getline" function but the same thing happens.
What is the error here?
Problem
Cannot write to file.
Why
void insertInfo(int info) {
std::fstream stream("infoFile.txt"); // Open the file
Opens file with default permissions, which includes reading. The C++ Standard says I should expect "r+" behaviour and the C Standard says a file opened with "r+" behaviour must exist in order to be read (Someone please add a link if you have one). You cannot create a new file. This is problem 1. The Asker has dealt with this problem by providing a file.
Note: take care when working with files via relative paths. The program's working directory may not be where you think it is. This is problem 1a. It appears that the Asker has this taken care of for the moment.
while (!stream.eof()) {
Common bug. For more details see Why is iostream::eof inside a loop condition considered wrong? In this case since all you're looking for is the end of the file, the fact that the file hasn't been opened at all or has encountered any read errors is missed. Since a file in an error state can never reach the end of the file this quickly becomes an infinite loop. This is problem 2.
std::string a{};
// getline(stream, a); <--- Tryied this, didn't work neither
stream.ignore(99, '\n');
Always test IO transactions for success. This call can fail unchecked.
} // Skip to the last line without any number, in theory
Assuming nothing has gone wrong, and since we're not checking the error state assuming's all we can do, the file has reached the end and is now in the EOF error state. We can't read from or write to the stream until we clear this error. This is problem number 3 and likely the problem the Asker is struggling with.
std::cout << info << std::endl; // Check if the output it's correct (Wich is)
stream << info; // Insert the info
This can fail unchecked.
stream.close(); // Close the file
This is not necessary. The file will be closed when it goes out of scope.
}
Solution
void insertInfo(int info) {
std::fstream stream("infoFile.txt"); // Open the file
while (!stream.eof()) {
stream.ignore(99, '\n');
} // Skip to the last line without any number, in theory
std::cout << info << std::endl; // Check if the output it's correct (Wich is)
stream.clear(); // Added a call to clear the error flags.
stream << info; // Insert the info
stream.close(); // Close the file
}
Now we can write to the file. But let's improve this shall we?
void insertInfo(int info) {
std::fstream stream("infoFile.txt");
while (stream.ignore(99, '\n')) // moved ignore here. now we ignore, then test the result
{
}
stream.clear();
stream << info << '\n'; // added a line ending. Without some delimiter the file
// turns into one big number
}
Note that this isn't exactly kosher. If any ignore fails for any reason, we bail out and possibly write over data because the code blindly clears and writes. I'm not spending much time here trying to patch this up because we can get really, really simple and solve the problem of creating a non-existent file at the same time.
void insertInfo(int info) {
std::fstream stream("infoFile.txt", std::ios::app);
stream << info << '\n';
}
Two lines and pretty much done. With app we append to the file. We do not need to find the end of the file, the stream automatically points at it. If the file does not exist, it is created.
Next improvement: Let people know if the write failed.
bool insertInfo(int info) {
std::fstream stream("infoFile.txt", std::ios::app);
return static_cast<bool>(stream << info << '\n');
}
If the file was not written for any reason, the function returns false and the caller can figure out what to do. The only thing left is to tighten up the stream. Since all we do is write to ti we don't need the permissiveness of a fstream. Always start with the most restrictive and move to the least. This helps prevent some potential errors by making them impossible.
bool insertInfo(int info) {
std::ofstream stream("infoFile.txt", std::ios::app);
return static_cast<bool>(stream << info << '\n');
}
Now we use an ofstream and eliminate all the extra overhead and risk brought in by the ability to read the stream when we don't read the stream.
I've been having a nightmare this evening trying to get some very simple I/O functionality going. As embarrassing as it is, I've had some great help from people on here!
My current issue is that I'm attempting to use ifstream.open() and it simply is not opening the file. This is confirmed by getline(ifstream,line); returning false on it's first call.
Here is a copy paste of the current code:
std::string FSXController::readLine(int offset, FileLookupFlag flag)
{
// Storage Buffer
string line;
streampos sPos(offset);
try
{
// Init stream
if (!m_ifs.is_open())
m_ifs.open("C:\\Users\\guyth\\Documents\\test.txt", fstream::in);
}
catch (int errorCode)
{
showException(errorCode);
return "";
}
// Set stream to read input line
m_ifs.seekg(sPos);
if (!getline(m_ifs, line))
return "";
// Close stream if no multiple selection required
if (flag == FileLookupFlag::single)
m_ifs.close();
return line;
}
This code is in 'bug fix mode' and so therefore is pretty messy, don't worry too much about that, cleanup will happen when this method is finally working.
I have tried:
Absolute file path
Saving path into string and then calling the .c_str() method.
Running VS 2015 in Administrator mode
Ensuring file has read/wright access
Ensuring no duplicate file extensions
Yes the file definitely has content! :D
I'm kinda out of ideas now and am really not sure why this file is refusing to load.
The condition: if (!getline(m_ifs, line)) Repeatedly returns true... :(
EDIT: I've just tried checking m_ifs.fail() immediately after the open and it returns true, so we know the fail flag was triggered :/
Thanks
Guy
Enable exceptions before opening the stream:
m_ifs.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
Otherwise m_ifs.open won't throw.
And you have to catch std::ifstream::failure:
try {
m_ifs.open("C:\\Users\\guyth\\Documents\\test.txt", fstream::in);
}
catch (std::ifstream::failure e) {
std::cerr << "Exception opening file: " << std::strerror(errno) << "\n";
}
See ios::exceptions for more details.
I was wondering if anyone could help me with my code (C++)? This is the function that will not work. When I run it, Windows pops up and says "This program has stopped working." Here is the code that will not run (it's a little long, but the program is proprietary and I appreciate any help):
void ClassName::loadGrades(){
string temp;
int count=0;
ifstream labErnIn("labGradesErn.txt");
if(labErnIn.is_open()){
count=0;
while(labErnIn.good()){
getline(labErnIn, temp);
float tempF = ::atof(temp.c_str());
labGradesErn[count] = tempF;
if(labGradesErn[count]==0 && count==0) labGradesErn[count]=-1;
count++;
}
labGradesErn[count-1]=-1;
labErnIn.close();
}
else{
cout << "Unable to open file labGradesErn.txt" << endl;
}
// I repeat this for three other sections, same code, different var names.
// From 'ifstream...' to 'Unable to open file'
}
All variables not declared in this function are declared elsewhere.
Thanks, I really appreciate any and all help!
If labGradesErn is a fixed array, you risk an array overrun sooner or later. If it is a std::vector, you should use push_back() to append elements, because increasing the index doesn't increase the vector.
Another point is your while loop. You don't test if getline succeeds and you should loop on getline instead of good
while (getline(labErnIn, temp)) {
...
}
I have problem running and debugging this piece of code:
bool readSectionHeaders(char* path, int numOfSections, int peSectionsOff, IMAGE_SECTION_HEADER* out) {
bool retr = false; //return value
//open file
FILE* file;
file = fopen (path, "rb");
if(file == NULL) {
perror("WRG"); //TODO
return false;
}
do { //do while(false) only for easier error correction
//seek to first section
fseek(file, peSectionsOff, SEEK_SET);
//read all sections
unsigned int count;
IMAGE_SECTION_HEADER sectionHeaders[numOfSections];
count = fread(sectionHeaders, sizeof(IMAGE_SECTION_HEADER), numOfSections, file);
//check Bytes count
if(count != sizeof(IMAGE_SECTION_HEADER)*numOfSections) {
break;
}
//copy sections
memcpy(out, sectionHeaders, count);
//exit successfully
retr = true;
} while(false);
//exit
fclose(file);
return retr;
}
What is strange is that it returns false even when it reads the file. I tried to debug it and here is the strangest part.
I go line by line until this one
if(file == NULL) {
Then even though file is not NULL it skips perror and moves to
return false;
But does not return at all.
I again go line by line until
retr = true;
where it seems to do something, however retr remains false.
Then it closes file and returns with false.
I have never come across something like this.
I tried cleaning project, rebuilding, even deleting files and redownloading them from subversion. Before using this function, I use similar one - I read PE headers. So I though a problem could be with reading the file but it doesn§t explain debug behavior.
After returning from function, I use perror and it writes No error.
I use mingw with QtCreator.
Thanks in advance.
I would do something more like this, if it is able to load the whole array then it will return true.
std::ofstream file(path, std::ios::binary);
if(!file) {
std::cerr << "failed to load file" << std::endl;
return false;
}
file.seekg (peSectionsOff, ios::beg);
IMAGE_SECTION_HEADER sectionHeaders[numOfSections];
size_t size=sizeof(sectionHeaders)*numOfSections;
return //return true if the whole buffer is filled
file.readsome(static_cast<char*>(sectionHeaders), size) == size;
UNTESTED
this might be helpful
http://en.cppreference.com/w/cpp/io
Ok, this was both my and mingw's problem. I've re-installed whole QtSDK with no effect. Then I installed different version of mingw and set qt creator up to use it. Now debugger works without problem. I'm not sure what happened but cerr << "TEST"; also stopped working with the old mingw and this is 100% correct.
As 111111 suggested, problem was with if break clause. I thought read returns number of bytes read and this was simply not true :).
Now it is working, thanks to 111111 for his suggestion :).
What's the correct way to check for a general error when sending data to an fstream?
UPDATE: My main concern regards some things I've been hearing about a delay between output and any data being physically written to the hard disk. My assumption was that the command "save_file_obj << save_str" would only send data to some kind of buffer and that the following check "if (save_file_obj.bad())" would not be any use in determining if there was an OS or hardware problem. I just wanted to know what was the definitive "catch all" way to send a string to a file and check to make certain that it was written to the disk, before carrying out any following actions such as closing the program.
I have the following code...
int Saver::output()
{
save_file_handle.open(file_name.c_str());
if (save_file_handle.is_open())
{
save_file_handle << save_str.c_str();
if (save_file_handle.bad())
{
x_message("Error - failed to save file");
return 0;
}
save_file_handle.close();
if (save_file_handle.bad())
{
x_message("Error - failed to save file");
return 0;
}
return 1;
}
else
{
x_message("Error - couldn't open save file");
return 0;
}
}
A few points. Firstly:
save_file_handle
is a poor name for an instance of a C++ fstream. fstreams are not file handles and all this can do is confuse the reader.
Secondly, as Michael pints out, there is no need to convert a C++ string to a C-string. The only time you should really find yourself doing this is when interfacing with C-style APIS, and when using a few poorly designed C++ APIs, such as (unfortunately) fstream::open().
Thirdly, the canonical way to test if a stream operation worked is to test the operation itself. Streams have a conversion to void * which means you can write stuff like this:
if ( save_file_handle << save_str ) {
// operation worked
}
else {
// failed for some reason
}
Your code should always testv stream operations, whether for input or output.
Everything except for the check after the close seems reasonable. That said, I would restructure things slightly differently and throw an exception or use a bool, but that is simply a matter of preference:
bool Saver::output()
{
std::fstream out(_filename.c_str(),std::ios::out);
if ( ! out.is_open() ){
LOG4CXX_ERROR(_logger,"Could not open \""<<filename<<"\"");
return false;
}
out << _savestr << std::endl;
if ( out.bad() ){
LOG4CXX_ERROR(_logger,"Could not save to \""<<filename<<"\"");
out.close();
return false;
}
out.close();
return true;
}
I should also point out that you don't need to use save_str.c_str(), since C++ iostreams (including fstream, ofstream, etc.) are all capable of outputting std::string objects. Also, if you construct the file stream object in the scope of the function, it will automatically be closed when it goes out of scope.
Are you absolutely sure that save_file_handle doesn't already have a file associated (open) with it? If it does then calling its open() method will fail and raise its ios::failbit error flag -- and any exceptions if set to do so.
The close() method can't fail unless the file isn't open, in which case the method will raise the ios::failbit error flag. At any rate, the destructor should close the file, and do so automatically if the save_file_handle is a stack variable as in your code.
int Saver::output()
{
save_file_handle.open(file_name.c_str());
if (save_file_handle.fail())
{
x_message("Error - file failed to previously close");
return 0;
}
save_file_handle << save_str.c_str();
if (save_file_handle.bad())
{
x_message("Error - failed to save file");
return 0;
}
return 1;
}
Alternatively, you can separate the error checking from the file-saving logic if you use ios::exceptions().
int Saver::output()
{
ios_base::iostate old = save_file_handle.exceptions();
save_file_handle.exceptions(ios::failbit | ios::badbit);
try
{
save_file_handle.open(file_name.c_str());
save_file_handle << save_str.c_str();
}
catch (ofstream::failure e)
{
x_message("Error - couldn't save file");
save_file_handle.exceptions(old);
return 0;
}
save_file_handle.exceptions(old);
return 1;
}
You might prefer to move the call to save_file_handle.exceptions(ios::failbit | ios::badbit) to the constructor(s). Then you can get rid of the statements that reset the exceptions flag.