My program opens and writes to several files incrementally but at some seemingly arbitrary point appending text to an already existing file fails. Here's the offending piece of code:
bool append_to_file(std::string const &Path, std::string const &What) {
std::ofstream FStream(Path, std::ios::out | std::ios::app);
if (!FStream) {
std::cerr << "OPEN FAILED" << std::endl;
return false;
}
FStream << What;
if (!FStream) {
std::cerr << "WRITE FAILED" << std::endl;
return false;
}
return true;
}
When this function fails, the first check succeeds but the second doesn't and prints:
WRITE FAILED. The file in question definitely does exist in the filesystem both before and after the function is called and has read and write permissions set. I can't make sense of this, why would opening the file succeed but appending fail in this scenario?
EDIT: this is not reproducible given the information I've provided and should be closed.
This works for me:
#include <string>
#include <fstream>
#include <iostream>
int append_to_file(std::string const& Path, std::string const& What) {
std::fstream FStream(Path,std::ios_base::app);
if (!FStream) {
std::cerr << "OPEN FAILED" << std::endl;
return 1;
}
FStream << What;
if (!FStream) {
std::cerr << "WRITE FAILED" << std::endl;
return 2;
}
return 0;
}
int main() {
int res = append_to_file("Tester.txt", "HIIII");
std::cout << res;
}
In the example you provided, had you #included <iostream>, <string> and <fstream>? Also, when opening with std::ios_base::app, you don't have to have to open with std::ios_base::out. Also, I changed the return true; and return false; so that it returns a number depending on where it failed. This makes it easier to trace the error. Finally, I changed std::ofstream to std::fstream, because we are opening customly. After that, it worked perfectly.
Related
ifstream fin;
fin.open("C:\\Users\\Zach\\Desktop\\input.txt");
if (!fin)
{
cout << "e";
}
e is printing whether I use the full pathway or just input.txt from a resource file
If the file exists, make sure that you have got the path specified correctly. Since you're running on Windows, you can verify the full path to your executable with the following code.
#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>
#define BUFSIZE 4096
std::string getExePath()
{
char result[BUFSIZE];
return std::string(result, GetModuleFileName(NULL, result, BUFSIZE));
}
int main()
{
std::ifstream infile("input.txt");
if (infile.is_open())
{
std::cout << "Success!" << std::endl;
infile.close();
}
else
{
std::cout << "Failed to open input.txt!" << std::endl;
std::cout << "Executable path is ->" << getExePath() << "<-" << std::endl;
}
return 0;
}
This will allow you to verify that your path to the input file is correct, assuming that it's collocated with your executable.
You need to direct output into the ifstream object by using fin << "string"; and not directing to standard out via cout.
Properly testing function return values is fundamental, but it can quickly clutter the code and make it hard to read, like in the simple example below:
#include <iostream>
#include <fstream>
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
return 0;
}
I have thought of a solution reducing cluttering by using a macro and c++11 lambda functions like this:
#include <iostream>
#include <fstream>
#define RETURN_IF(X,Y,Z) if ( X ) { Y ; return Z; }
auto open_file_error = [](const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
};
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
return 0;
}
As you can see, the main function is less cluttered. Do you think that there are drawbacks to doing it like that or could it be a method to largely use?
Note that I use several macros to handle cases with or without a return value, for testing equality with a value, etc.
I propose the new version below to take into account two things:
- the answers and comments about the preference on using exceptions instead of return values;
- put away the emphasis on std::ifstream specific errors which are not the subject of the question.
#include <iostream>
#include <fstream>
#include <exception>
class OurExceptionForTheExternalLibraryFailure : public std::exception {};
#define CLEANUP_AND_THROW_IF(X,Y,Z) if ( X ) { Y ; throw Z; }
/* Return true in case of succes and false otherwise */
bool anyExternalFunction(const std::string& aString)
{
std::ifstream ifs(aString.c_str());
if (ifs.is_open())
{
ifs.close();
return true;
}
else
{
return false;
}
}
auto this_external_function_error_cleanup = [](const std::string& aString)
{
std::cerr << "The external function failed " << aString << std::endl;
// other stuff
};
int main(int argc, char **argv)
{
try
{
std::string aString = "/usr/include/malloc.h";
bool functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
std::cout << "Passed the first error handling" << std::endl;
aString = "/this/file/does/not/exist";
functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
}
catch (const OurExceptionForTheExternalLibraryFailure& e)
{
std::cerr << "Catched OurExceptionForTheExternalLibraryFailure. There was an error" << std::endl;
}
return 0;
}
What do you think about this new version (which still uses a macro, though...) ?
Well, if you are already using lambdas, and you don't want all that testing code everywhere, you could always do something like (NOTE: uncompiled/untested code,)
template <typename FileReader>
void with_file(std::string file, FileReader&& reader) {
std::ifstream in(file);
if (in) {
reader(in);
} else {
throw std::runtime_error("Failed to open file: " + file); // NOTE: I'm being lazy here
}
}
int main(...) {
with_file("foo.txt", [](auto& in) {
// do something with the stream
});
}
.. but it's a matter of preference, I like exceptions, lambdas and small utility functions, but some may not...
This is pretty much a textbook example of when to use exceptions.
You don't, however, have to write your own code to test for a file opening correctly, and throwing an exception (and so on) when it fails. Iostreams already support that fairly directly, so you can write code something like this:
#include <fstream>
#include <iostream>
int main() {
try {
std::ifstream in("/usr/include/malloc.h");
in.exceptions(std::ios::failbit);
in.close();
std::cout << "passed first test.\n";
std::ifstream in2("/this/file/does/not/exist");
in2.exceptions(std::ios::failbit);
in2.close();
std::cout << "Passed second test\n";
}
catch (std::system_error &f) {
std::cerr << "Failed to open file: " << f.what() << "\n";
}
}
Of course, if you want to get the try/catch out of main, you can do that as well. I'm not sure you gain much from doing so though.
More generally, however, exceptions are clearly the right tool for this job. For other functions that don't provide a way to get exceptions reported as exceptions, you may have to write a wrapper of your own. Either way, however, if you have a function that has some range of normal return values, and one (or a few) "special" values in indicate failure (and similar) that's a pretty decent indication that it's indicating an exceptional condition via the return value--and the right way to deal with exceptional conditions is via exceptions rather than return values.
Rather than try to reiterate the (long) list of why/when/how to use exception handling, I'll refer you (as a starting point) to Herb Sutter's old article on when and how to use exceptions.
Suggest this as a much cleaner example. NOW USING EXCEPTIONS...
I haven't tested that it's 100% the same behaviour as your example (which I appreciate is just that; an example).
By the way, MFC has a "SUCCESS" macro that does a similar check to your "RETURN_IF". I don't like that macro either...
#include <iostream>
#include <fstream>
#include <string>
void TestForFileOpen(const std::string& filename)
{
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
throw std::exception("Failed");
}
}
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const std::string& filename)
{
try
{
TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(filename);
}
catch (...)
{
return 1;
}
return 0;
}
A more general example with a custom API:
#include <iostream>
#include <fstream>
#include <string>
class IFileTester
{
public:
virtual ~IFileTester() {}
// throws if file cannot be opened
virtual void TestForFileOpen(const std::string& filename) const = 0;
};
class IfStreamFileTester : public IFileTester // implement as many versions as you need
{
public:
virtual void TestForFileOpen(const std::string& filename) const
{
// implement this in terms of ifstream
std::ifstream ifs(filename.c_str());
// thanks #Jerry-Coffin
ifs.exceptions(std::ios::failbit);
}
};
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const IFileTester& fileTester, const std::string& filename)
{
try
{
fileTester.TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
IFileTester& fileTester = IfStreamFileTester();
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(fileTester, filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(fileTester, filename);
}
catch (...)
{
return 1;
}
return 0;
}
Looks okay to me. I wouldn't put all your eggs into this basket because you don't have to make it much more complicated to run into limitations with preprocessor syntax but, as it is, this is fine.
I'm trying to read a whole text-file using a simple ifstream.
The code
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main()
{
std::string line;
std::vector<std::string> DataArray;
//std::vector<std::string> QueryArray;
std::string filename = "c:\\helloworld.txt";
std::ifstream myfile(filename.c_str());
//std::ifstream qfile("queries.txt");
if (myfile.fail()) {
perror("c:\\helloworld.txt");
getchar();
return -1;
}
if (!myfile) //Always test the file open.
{
std::cout << "Error opening output file" << std::endl;
system("pause");
return -1;
}
while (std::getline(myfile, line))
{
DataArray.push_back(line);
}
/*if (!qfile) //Always test the file open.
{
std::cout << "Error opening output file" << std::endl;
system("pause");
return -1;
}
while (std::getline(qfile, line))
{
QueryArray.push_back(line);
}*/
//std::cout << QueryArray[20] << std::endl;
std::cout << DataArray[7] << std::endl;
return 0;
}
The result
I am getting the following result:
Error opening output file
The text-file my_text_file.txt is rightly in the same directory of my program.
Final question
It looks like it can't read my_text_file.txt, why? Did I do something wrong?
Also changing
std::ifstream myfile("c:\\my_text_file.txt");
to
std::ifstream myfile("my_text_file.txt");
doesn't solve the problem.
I think your error can be caused of many different reasons.
There is a handy Error-Message-Interpreteur thing called perror(c++ reference perror).
A standard way to use it(after declaring the file):
if(myFile.fail()){
perror("my_text_file.txt");
return -1;
}
That should give you a more detailed report on the issue, and it can tell you if the problem really is the directory of the file. Hope this helps.
Using GCC 4.7.3 on Cygwin 1.7.24. Compiler options include: -std=gnu++11 -Wall -Wextra
I am working on a command line application and I needed to be able to load and save a set of strings so I wrote a quick wrapper class around std::set to add load and save methods.
// KeySet.h
#ifndef KEYSET_H
#define KEYSET_H
#include <cstdlib>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <string>
#include <set>
#include <iostream>
#include <fstream>
inline bool file_exists (const std::string& filename)
{
/*
Utility routine to check existance of a file. Returns true or false,
prints an error and exits with status 2 on an error.
*/
struct stat buffer;
int error = stat(filename.c_str(), &buffer);
if (error == 0) return true;
if (errno == ENOENT) return false;
std::cerr << "Error while checking for '" << filename << "': " << strerror(errno) << std::endl;
exit (2);
}
class KeySet
{
private:
std::string filename;
std::set<std::string> keys;
public:
KeySet() {}
KeySet(const std::string Pfilename) : filename(Pfilename) {}
void set_filename (const std::string Pfilename) {filename = Pfilename;}
std::string get_filename () {return filename;}
auto size () -> decltype(keys.size()) {return keys.size();}
auto cbegin() -> decltype(keys.cbegin()) {return keys.cbegin();}
auto cend() -> decltype(keys.cend()) {return keys.cend();}
auto insert(const std::string key) -> decltype(keys.insert(key)) {return keys.insert(key);}
void load ();
void save ();
};
void KeySet::load ()
{
if (file_exists(filename)) {
errno = 0;
std::ifstream in (filename, std::ios_base::in);
if (in.fail()) {
std::cerr << "Error opening '" << filename << "' for reading: " << strerror(errno) << std::endl;
exit (2);
}
std::string token;
if (token.capacity() < 32) token.reserve(32);
while (in >> token) keys.insert(token);
if (!in.eof()) {
std::cerr << "Error reading '" << filename << "': " << strerror(errno) << std::endl;
exit (2);
}
in.clear(); // need to clear flags before calling close
in.close();
if (in.fail()) {
std::cerr << "Error closing '" << filename << "': " << strerror(errno) << std::endl;
exit (2);
}
}
}
void KeySet::save ()
{
errno = 0;
std::ofstream out (filename, std::ios_base::out);
if (out.fail()) {
std::cerr << "Error opening '" << filename << "' for writing: " << strerror(errno) << std::endl;
exit (2);
}
for (auto key = keys.cbegin(), end = keys.cend(); key != end; ++key) {
out << *key << std::endl;
}
out.close();
if (out.fail()) {
std::cerr << "Error writing '" << filename << "': " << strerror(errno) << std::endl;
exit (2);
}
}
#endif
//
Here's a quick program to test the load method.
// ks_test.cpp
#include "KeySet.h"
int main()
{
KeySet test;
std::string filename = "foo.keys.txt";
test.set_filename(filename);
test.load();
for (auto key = test.cbegin(), end = test.cend(); key != end; ++key) {
std::cout << *key << std::endl;
}
}
The data file just has "one two three" in it.
When I go to run the test program, I get the following error from my test program:
$ ./ks_test
Error closing 'foo.keys.txt': No error
Both cppreference.com and cplusplus.com say that the close method should set the fail bit on error. The save method works fine, and the load method works correctly if I comment out the error check after the close. Should this really work or have I misunderstood how close is supposed to work? Thanks in advance.
Edited to clarify, fix typo's and adjust code per Joachim Pileborg's and Konrad Rudolph's comments.
Edited to add solution to the code.
You have two errors here: The first is about how you do your reading, more specifically the loop for reading. The eof flag will not be set until after you tried to read and the read failed. Instead you should do like this:
while (in >> token) { ... }
Otherwise you will loop one time to many and try to read beyond the end of the file.
The second problem is the one you notice, and it depends on the the first problem. Since you try to read beyond the end of the file, the stream will set failbit causing in.fail() to return true even though there is no real error.
As it turns out, the close method for ifstream (and I assume all other IO objects) DOES NOT clear the error flags before closing the file. This means you need to add an explicit clear() call before you close the stream after end of file if you are checking for errors during the close. In my case, I added in.clear(); just before the in.close(); call and it is working as I expect.
I want to input some contents to a file, but I'd like to check first if a file with the name I wish to create exists. If so, I don't want to create any file, even if the file is empty.
My attempt
bool CreateFile(char name[], char content[]){
std::ofstream file(name);
if(file){
std::cout << "This account already exists" << std::endl;
return false;
}
file << content;
file.close();
return true;
}
Is there any way to do what I want?
Assuming it is OK that the operation is not atomic, you can do:
if (std::ifstream(name))
{
std::cout << "File already exists" << std::endl;
return false;
}
std::ofstream file(name);
if (!file)
{
std::cout << "File could not be created" << std::endl;
return false;
}
...
Note that this doesn't work if you run multiple threads trying to create the same file, and certainly will not prevent a second process from "interfering" with the file creation because you have TOCTUI problems. [We first check if the file exists, and then create it - but someone else could have created it in between the check and the creation - if that's critical, you will need to do something else, which isn't portable].
A further problem is if you have permissions such as the file is not readable (so we can't open it for read) but is writeable, it will overwrite the file.
In MOST cases, neither of these things matter, because all you care about is telling someone that "you already have a file like that" (or something like that) in a "best effort" approach.
you can also use Boost.
boost::filesystem::exists( filename );
it works for files and folders.
And you will have an implementation close to something ready for C++14 in which filesystem should be part of the STL (see here).
Try
ifstream my_file("test.txt");
if (my_file)
{
// do stuff
}
From: How to check if a file exists and is readable in C++?
or you could use boost functions.
Try this (copied-ish from Erik Garrison: https://stackoverflow.com/a/3071528/575530)
#include <sys/stat.h>
bool FileExists(char* filename)
{
struct stat fileInfo;
return stat(filename, &fileInfo) == 0;
}
stat returns 0 if the file exists and -1 if not.
As of C++17 there is:
if (std::filesystem::exists(pathname)) {
...
Looked around a bit, and the only thing I find is using the open system call. It is the only function I found that allows you to create a file in a way that will fail if it already exists
#include <fcntl.h>
#include <errno.h>
int fd=open(filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
/* file exists or otherwise uncreatable
you might want to check errno*/
}else {
/* File is open to writing */
}
Note that you have to give permissions since you are creating a file.
This also removes any race conditions there might be
I just saw this test:
bool getFileExists(const TCHAR *file)
{
return (GetFileAttributes(file) != 0xFFFFFFFF);
}
C++17, cross-platform: Using std::filesystem::exists and std::filesystem::is_regular_file.
#include <filesystem> // C++17
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
bool CreateFile(const fs::path& filePath, const std::string& content)
{
try
{
if (fs::exists(filePath))
{
std::cout << filePath << " already exists.";
return false;
}
if (!fs::is_regular_file(filePath))
{
std::cout << filePath << " is not a regular file.";
return false;
}
}
catch (std::exception& e)
{
std::cerr << __func__ << ": An error occurred: " << e.what();
return false;
}
std::ofstream file(filePath);
file << content;
return true;
}
int main()
{
if (CreateFile("path/to/the/file.ext", "Content of the file"))
{
// Your business logic.
}
}
The easiest way to do this is using ios :: noreplace.