I am implementing file saving functionality within a Qt application using C++.
I am looking for a way to check to see if the selected file already exists before writing to it, so that I can prompt a warning to the user.
I am using an std::ofstream and I am not looking for a Boost solution.
This is one of my favorite tuck-away functions I keep on hand for multiple uses.
#include <sys/stat.h>
// Function: fileExists
/**
* Check if a file exists
*
* #param[in] filename - the name of the file to check
*
* #return true if the file exists, else false
*/
bool fileExists(const std::string& filename)
{
struct stat buf;
if (stat(filename.c_str(), &buf) != -1)
{
return true;
}
return false;
}
I find this much more tasteful than trying to open a file if you have no immediate intentions of using it for I/O.
bool fileExists(const char *fileName)
{
ifstream infile(fileName);
return infile.good();
}
This method is so far the shortest and most portable one. If the usage is not very sophisticated, this is one I would go for. If you also want to prompt a warning, I would do that in the main.
fstream file;
file.open("my_file.txt", ios_base::out | ios_base::in); // will not create file
if (file.is_open())
{
cout << "Warning, file already exists, proceed?";
if (no)
{
file.close();
// throw something
}
}
else
{
file.clear();
file.open("my_file.txt", ios_base::out); // will create if necessary
}
// do stuff with file
Note that in case of an existing file, this will open it in random-access mode. If you prefer, you can close it and reopen it in append mode or truncate mode.
With std::filesystem::exists of C++17:
#include <filesystem> // C++17
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::path filePath("path/to/my/file.ext");
std::error_code ec; // For using the noexcept overload.
if (!fs::exists(filePath, ec) && !ec)
{
// Save to file, e.g. with std::ofstream file(filePath);
}
else
{
if (ec)
{
std::cerr << ec.message(); // Replace with your error handling.
}
else
{
std::cout << "File " << filePath << " does already exist.";
// Handle overwrite case.
}
}
}
See also std::error_code.
In case you want to check if the path you are writing to is actually a regular file, use std::filesystem::is_regular_file.
Try ::stat() (declared in <sys/stat.h>)
One of the way would be to do stat() and check on errno.
A sample code would look look this:
#include <sys/stat.h>
using namespace std;
// some lines of code...
int fileExist(const string &filePath) {
struct stat statBuff;
if (stat(filePath.c_str(), &statBuff) < 0) {
if (errno == ENOENT) return -ENOENT;
}
else
// do stuff with file
}
This works irrespective of the stream. If you still prefer to check using ofstream just check using is_open().
Example:
ofstream fp.open("<path-to-file>", ofstream::out);
if (!fp.is_open())
return false;
else
// do stuff with file
Hope this helps.
Thanks!
Related
Hello stack overflow community. I came here as a last resort because i probably made a stupid mistake i cannot see myself.
The question im asking is for some reason when i try to read a file with an absolute path(or relative, you can see i tried that in my code) it cannot read the file for some unknown reason(atleast to me). This is a small thing for a big project im working on. Thank you guys!
main.cpp
#include <iostream>
#include <fstream>
#include <filesystem>
#include <unistd.h>
#include <string>
std::string openf() {
FILE* pipe = popen("zenity --file-selection", "r"); // open a pipe with zenity
if (!pipe) return "ERROR"; // if failed then return "ERROR"
char buffer[912]; // buffer to hold data
std::string result = ""; // result that you add too
while(!feof(pipe)) { // while not EOF read
if(fgets(buffer, 912, pipe) != NULL) // get path and store it into buffer
result += buffer; // add buffer to result
}
//I thought i needed to convert the absolute path to relative but i did not after all
// char cwd[10000];
// getcwd(cwd, 10000); // get cwd(current working directory)
// result = std::filesystem::relative(result, cwd); // convert the absolute path to relative with cwd
pclose(pipe); // cleanup
return result;
}
std::string readf(std::string filename){
std::string res;
std::ifstream file;
file.open(filename.c_str());
if(file.is_open()) {
while(file){
res += file.get();
}
}else {
std::cout << "failed to open file " + filename;
}
return res;
}
int main( void ){
std::string file = openf();
std::cout << file << std::endl;
std::string str = readf(file);
std::cout << str << std::endl;
return 0;
}
output
/home/meepmorp/Code/Odin/test/test.odin
failed to open file /home/meepmorp/Code/Odin/test/test.odin
It seems zenity, which you use as file chooser, outputs an extra newline after the file name, which you include in the name. In Linux, files can actually contain embedded newline characters in their name, and you actually try to open "test.odin\n" instead of "test.odin".
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.
I use an fstream object to write data to a text file. I write some initial data to it once and then write more data to it in a loop. Every time before writing to the file stream, I check whether it's open. Is this unnecessary? Should I only check once immediately after creating the fstream object?
Basically, I do this:
#define STOP 32700 // some value that indicates no more data is available
#include <string>
#include <exception>
#include <fstream>
int main (int argc, char* argv[])
{
try {
double data[5] {};
const std::string output_file_name {"name.txt"}
std::fstream outputFile (output_file_name, std::ios::out | std::ios::trunc);
if (outputFile.is_open()) // successfully opened file
outputFile << "initial text\n";
else // if text file could not be opened
throw Fstream_Exception;
/* do some other stuff (in various threads) */
do { // ok, now get data and write it to the file!
getData(&data[0]);
if (outputFile.is_open())
outputFile << data[0] << '\n';
else
throw Fstream_Exception;
} while (data[0] != STOP);
}
catch (Fstream_Exception& fstream_exception) {
/* handle exception */
}
}
The stream itself can throw exceptions when an error occurs. Just use its exceptions() method and pass the types of errors you want it to detect. This is more convenient than checking the state flags after each operation.
I have a requirement, I need to use printf and cout to display the data into console and file as well.
For printf I have done it but for cout I am struggling, how to do it?
#ifdef _MSC_VER
#define GWEN_FNULL "NUL"
#define va_copy(d,s) ((d) = (s))
#else
#define GWEN_FNULL "/dev/null"
#endif
#include <iostream>
#include <fstream>
using namespace std;
void printf (FILE * outfile, const char * format, ...)
{
va_list ap1, ap2;
int i = 5;
va_start(ap1, format);
va_copy(ap2, ap1);
vprintf(format, ap1);
vfprintf(outfile, format, ap2);
va_end(ap2);
va_end(ap1);
}
/* void COUT(const char* fmt, ...)
{
ofstream out("output-file.txt");
std::cout << "Cout to file";
out << "Cout to file";
}*/
int main (int argc, char *argv[]) {
FILE *outfile;
char *mode = "a+";
char outputFilename[] = "PRINT.log";
outfile = fopen(outputFilename, mode);
char bigfoot[] = "Hello
World!\n";
int howbad = 10;
printf(outfile, "\n--------\n");
//myout();
/* then i realized that i can't send the arguments to fn:PRINTs */
printf(outfile, "%s %i",bigfoot, howbad); /* error here! I can't send bigfoot and howbad*/
system("pause");
return 0;
}
I have done it in COUT(caps, the commented part for the code above) . But I want to use normal std::cout, so how can I override it. And it should work for both sting and variables like
int i = 5;
cout << "Hello world" << i <<endl;
Or are there anyway to capture stdout data, so that they can be easily written into file and console as well.
If you have another stream buffer, you can just replace std::cout's:
std::cout.rdbuf(some_other_rdbuf);
See http://en.cppreference.com/w/cpp/io/basic_ios/rdbuf.
You can swap the underlying buffers. Here is that done facilitated through RAII.
#include <streambuf>
class buffer_restore
{
std::ostream& os;
std::streambuf* buf;
public:
buffer_restore(std::ostream& os) : os(os), buf(os.rdbuf())
{ }
~buffer_restore()
{
os.rdbuf(buf);
}
};
int main()
{
buffer_restore b(std::cout);
std::ofstream file("file.txt");
std::cout.rdbuf(file.rdbuf());
// ...
}
Overriding the behaviour of std::cout is a really bad idea as other developers will have a hard time understanding that the use of std::cout doesn't behave as usual.
Make your intention clear with a simple class
#include <fstream>
#include <iostream>
class DualStream
{
std::ofstream file_stream;
bool valid_state;
public:
DualStream(const char* filename) // the ofstream needs a path
:
file_stream(filename), // open the file stream
valid_state(file_stream) // set the state of the DualStream according to the state of the ofstream
{
}
explicit operator bool() const
{
return valid_state;
}
template <typename T>
DualStream& operator<<(T&& t) // provide a generic operator<<
{
if ( !valid_state ) // if it previously was in a bad state, don't try anything
{
return *this;
}
if ( !(std::cout << t) ) // to console!
{
valid_state = false;
return *this;
}
if ( !(file_stream << t) ) // to file!
{
valid_state = false;
return *this;
}
return *this;
}
};
// let's test it:
int main()
{
DualStream ds("testfile");
if ( (ds << 1 << "\n" << 2 << "\n") )
{
std::cerr << "all went fine\n";
}
else
{
std::cerr << "bad bad stream\n";
}
}
This provides a clean interface and outputs the same for both the console and the file.
You may want to add a flush method or open the file in append mode.
I assume you have some code using std::cout and printf which you cannot modify, otherwise the most simple way to solve your problem would be to write to a different stream from cout and use fprintf rather than or in conjunction with printf.
By following that approach you could define both a new stream class that actually wrote both to standard output and to a given file, as well as a function that combined calls to both printf and fprintf.
However a much simpler approach is to use the tee program, originally from UNIX, which copies its input both to output and to a given file. With that you could simply call your program in this way:
your_program | tee your_log_file
Answers to this question lead to a few alternative implementations available for Windows. Personally I always install cygwin on my PC's to have UNIX/Linux utilities available.
If i guess correctly you want to log everything that goes to the output also into a file.
What you want is an observer pattern.
Replace all direct logging in your code with calls to a new relay.
The logging relay sends your messages to the observers.
One of your observers loggs the message to the screen.
The other one loggs to the file.
Avoid making your relay a singleton if possible.
This suggestion only works if you can edit all of your source files.
std::cout writes to stdout file you can do the following on Linux and Windows
#include <stdio.h>
#include <iostream>
int main()
{
freopen("test.txt", "w", stdout);
std::cout << "Hello strange stdout\n";
}
to change it back use the following taken from here
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
FILE *stream ;
if((stream = freopen("file.txt", "w", stdout)) == NULL)
exit(-1);
printf("this is stdout output\n");
stream = freopen("CON", "w", stdout);
printf("And now back to the console once again\n");
}
Note: The latter is windows only
cout is normally implemented as an object instance so you can't override it in the way that you would overload / override a function or a class.
Your best bet is not to fight that - yes you could build a my_cout and #define cout my_cout but that would make your code obtuse.
For readability I'd leave cout as it is. It's a standard and everyone knows what it can and can't do.
Try using a macro - something like this (you'll need to add the includes) :
#define MY_COUT(theos,printThis) { cout << printThis ; theos << printThis; }
void test()
{
ofstream myos;
myos.open("testfile", ios::trunc|ios::out);
int i = 7;
MY_COUT(myos, "try this numbers" << i << i + 1 << endl);
myos.close()
}
There's already a Boost class for this: tee
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.