How to create a file in a different directory in C++? - c++

#include <iostream>
#include <fstream>
#include <cstdlib>
int main() {
std::fstream f1("/tmp/test");
if (!f1) {
std::cerr << "f1 failed\n";
} else {
std::cerr << "f1 success\n";
}
FILE *f2 = fopen("/tmp/test", "w+");
if (!f2) {
std::cerr << "f2 failed\n";
} else {
std::cerr << "f2 success\n";
}
}
Creating a file in /tmp/ doesn't work for me using fstreams but it does with fopen. What could be the problem? (I get f1 failed and f2 success when /tmp/test doesn't already exist)

You have to tell the fstream you are opening the file for output, like this
std::fstream fs("/tmp/test", std::ios::out);
Or use ofstream instead of fstream, that opens the file for output by default:
std::ofstream fs("/tmp/test");

Your first method call does not automatically create a file: see fstream.
If you want your first method call to create a file, use:
std::fstream f1("/tmp/test", fstream::out);

I don't know which is the default mode for the fstream constructor, I tried with this and it worked
std::fstream f1("/tmp/test", std::fstream::in | std::fstream::out);
It creates a file for input and output, you should check the fstream documentation here

Related

std::getline with std::fstream

I am using std::fstream to read and write to the same file. I can see the write happening but not the read.
After searching the web, I got to know that I can not set in and app mode together. So, got rid of that and made it very simple of not passing any arguments.
I am very interested to know the reason why read is not happening.
Also, how do people read and write to the same file using same fstream?
My code:
#include<iostream>
#include<fstream>
int main() {
std::fstream* fs = new std::fstream("xx.txt");
*fs << "Hello" << std::endl;
(*fs).close(); // ?
std::string line;
while(std::getline(*fs, line)) {
std::cout << line << std::endl;
}
}
With this code, I can xx.txt contain "Hello" as its content but it does not go inside the while loop at all stating that reading failed.
How can I overcome this?
You forgot to reopen the stream. Actually you can't open a stream in both directions (at the same time).
So the steps are:
Open the stream for writing
Write data
Close the stream
Reopen the stream for reading
Read data
Close it (optional)
Your sample can be rewritten as:
#include <fstream>
#include <iostream>
int main()
{
const std::string file_path("xx.txt");
std::fstream fs(file_path, std::fstream::app);
if(fs) // Check if the opening has not failed
{
fs << "Hello" << std::endl;
fs.close();
}
fs.open(file_path, std::fstream::in);
if(fs) // Check if the opening has not failed
{
std::string line;
while(std::getline(fs, line))
{
std::cout << line << std::endl;
}
fs.close();
}
return 0;
}
Note that it is a good idea to check if the stream is successfully open before trying to use it.
I will try to explain the issue.
Statement std::fstream* fs = new std::fstream("xx.txt"); will open file if it exists in default mode "in|out" .
If the file does not exist then the call to open from inside of constructor std::fstream will fail. And this can be checked by checking failbit using function fail(). So you will explicitly need to call 'open' to use the fstream object for data input. Note: the new file will not be created unless you call 'close'.
You can test this by actually trying to open an existing file or new file you can see the difference.
So alternatively what you should do is always call 'open' which will work in both cases (if file exists or not).
#include<iostream>
#include<fstream>
int main() {
//std::fstream fs("xx.txt");
//std::cout << fs.fail() << std::endl; // print if file open failed or passed
std::fstream fs;
fs.open("xx.txt", std::fstream::in | std::fstream::out | std::fstream::app);
std::cout << fs.fail() << std::endl;
fs << "Hello" << std::endl;
if (fs.is_open())
{
std::cout << "Operation successfully performed\n";
fs.close();
}
else
{
std::cout << "Error opening file";
}
For reading the content of the file you will first need to close the file. And then reopen and read. As I understand once you start using the object fs for insertion you cannot read from it unless you explicitly close it and reopen.
fs.open("xx.txt", std::fstream::in | std::fstream::out);
std::string line;
while(std::getline(fs, line)) {
std::cout << line << std::endl;
}
std::cout << "end" << std::endl;
fs.close();
}

creating and reading/writing to files with fstream in C++

I'm looking to create a file, then open it and rewrite to it.
I've found I can create a file by simply doing this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream outfile ("test.txt");
outfile << "my text here!" << endl;
outfile.close();
return 0;
}
while this works to create the test file, I cannot open the file and then edit it. this (below) does not work even after the file is created.
outfile.open("test.txt", ios::out);
if (outfile.is_open())
{
outfile << "write this to the file";
}
else
cout << "File could not be opened";
outfile.close;
If by "does not work" you mean that the text is overwritten instead of appended, you need to specify std::ios::app as one of the flags to the call to open to have it append more data instead of overwriting everything.
outfile.open("test.txt", ios::out | ios::app);
The following example works fine for me:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream outfile ("test.txt");
outfile << "my text here!" << endl;
outfile.close();
outfile.open("test.txt", ios::out | ios::app );
if (outfile.is_open())
outfile << "write this to the file" << endl;
else
cout << "File could not be opened";
outfile.close();
return 0;
}
Produces the following text file:
my text here!
write this to the file
You can also do that with FOPEN. Some compilers will notice you that the function its OBSOLETE or DEPRECATED but for me its working good.
/* fopen example */
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ("myfile.txt","w");
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
fclose (pFile);
}
return 0;
}
More info here: http://www.cplusplus.com/reference/cstdio/fopen/

Not able to ofstream using __gnu_cxx::stdio_filebuf

This creates the file but it doesn't write anything.
std::ofstream outstream;
FILE * outfile;
outfile = fopen("/usr7/cs/test_file.txt", "w");
__gnu_cxx::stdio_filebuf<char> filebuf(outfile, std::ios::out);
outstream.std::ios::rdbuf(&filebuf);
outstream << "some data";
outstream.close();
fclose(outfile);
I know there are other easy solutions to achieve the output, but i need to use this non-standard filebuf to lock a file while editing, so that other process can't open the file.
I don't know why this is not working.
std::ostream already has a constructor doing the right thing:
#include <ext/stdio_filebuf.h>
#include <iostream>
#include <fcntl.h>
int main() {
auto file = fopen("test.txt", "w");
__gnu_cxx::stdio_filebuf<char> sourcebuf(file, std::ios::out);
std::ostream out(&sourcebuf);
out << "Writing to fd " << sourcebuf.fd() << std::endl;
}
Remember that stdio_filebuf won't close the FILE* when it is destroyed, so remember to do that yourself if you need it.

Detect if file is open in C++

Is there any way in C++ to detect if a file is already open in another program?.I want to delete and rewrite some files, but in case a file is opened I want to display an error message. I am using Windows OS.
Taking an action depending on the result of the "is file open query" is a race condition (the query returns false and then a program opens the file before your program attempts to delete it for example).
Attempt to delete the file using DeleteFile() and if it fails display the reason the file delete failed, using GetLastError(). See System Error Codes for the list of error codes (ERROR_SHARING_VIOLATION which states "The process cannot access the file because it is being used by another process.")
You can use CreateFile API function with the share mode of NULL, which opens the file for exclusive use.
You can use remove("filename") function.
you can use is_open() to check if the file is open. If it is you can close it or do somehting else.
Here is an exampe:
int main ()
{
fstream filestr;
filestr.open ("test.txt");
if (filestr.is_open())
{
filestr << "File successfully open";
filestr.close();
}
else
{
cout << "Error opening file";
}
return 0;
}
#include <iostream> // std::cout
#include <fstream> // std::ofstream
int main () {
std::ofstream ofs;
ofs.open ("example.txt");
if (ofs.is_open())
{
ofs << "anything";
std::cout << "operation successfully performed\n";
ofs.close();
}
else
{
std::cout << "Error opening file";
}
return 0;
}

How to check if a file exists before creating a new file

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.