C++ ofstream equivalent to Win32 CreateFile with CREATE_NEW - c++

In an application I want to be sure that I am writing a brand new (binary) file. In Win32 programming I know I can do this with CreateFile using CREATE_NEW, but I can't work out a pure C++ standard way.
Creates a new file, only if it does not already exist.
If the specified file exists, the function fails and the last-error code is set to ERROR_FILE_EXISTS (80).
If the specified file does not exist and is a valid path to a writable location, a new file is created.
I tried using std::ios::out | std::ios::binary | std::ios::ate then seeing if tellp gave me the start of the file or not, but apart from the obvious case that this would still overwrite an empty file, it also seems to truncate a non-empty file anyway as if I used std::ios::trunc...
This was on VS2013, although I assume this is not a compiler/library bug.

The C++ standard doesn't have an API guaranteeing a new file. When opening an existing file in write-only mode without specifying std::ios_base::app it is truncated (independent on whether std::ios_base::trunc is used). I don't know about Windows but on POSIX this would retain the original inode and processes already having opened the file can still access it.
If it is sufficient to get an open and empty file rather than a new one, omiting std::ios_base::in and std::ios_base::app should do the trick (note that opening an std::fstream or an std::ifstream implicitly adds std::ios_base::in).

Related

Are file contents deleted when a text file is opened in "ios::in|ios::out" mode?

I have red recently that when a text file is opened using ios::out mode then ios::trunc is available by default. So when i open a file using ios::in|ios::out mode, ios::trunc will be available automatically or not?
I think that contents will not be deleted because ios::in is also used and both the get pointer and put pointer will be initially pointing to the zeroth byte in the file.
Am i correct?
While out alone does imply trunc, in|out does not. The full details are enumerated here: https://en.cppreference.com/w/cpp/io/basic_filebuf/open
If you want to write to a file but not destroy the existing contents, you can also use app (which implies out). Absent either in or app, any existing contents will be destroyed by out.

How to share file delete privilege when I opening a file by ifstream

I want to make the file that can be delete when it was opened by ifstream.
I know it is easy when using Windows API: CreateFile
CreateFile(...,FILE_SHARE_DELETE,...)
But when I test with opening a file by ifstream.
It can't be deleted when I opening it.
I didn't find any document about setting attribute such like FILE_SHARE_DELETE on ifstream.
How should I do to solve this problem?
Visual Studio's version of std::ifstream has a non-standard constructor and a non-standard open() overload that both have an extra optional _Prot parameter for specifying "file protection/sharing flags" (see _fsopen() for the list of available flags). However, delete sharing is not one of supported flags.
There is an alternative, though. Visual Studio's version of both std::ifstream and std::ofstream have non-standard constructors that accept a FILE* for the file access. You can wrap a HANDLE from CreateFile() into a FILE* using Microsoft's _open_osfhandle() and _fdopen() functions, for example (error handling removed for brevity):
Can I use CreateFile, but force the handle into a std::ofstream?
HANDLE file_handle = CreateFile(...,FILE_SHARE_DELETE,...);
int file_descriptor = _open_osfhandle((intptr_t)file_handle, _O_RDONLY);
FILE* file = _fdopen(file_descriptor, "r");
std::ifstream stream(file);
...
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
If you need something more portable to non-Microsoft compilers, you will likely have to resort to writing a custom std::basic_streambuf class (or maybe derived from std::filebuf) to wrap your HANDLE, and then pass an object of that class to the std::basic_istream constructor directly.
File permissions differ by operating system:
Windows has:
Whole-file access-sharing for read, write, or delete
*nix systems provide read, write, and execute permissions, but as far as delete permissions, all that is needed is:
write+execute permission on the parent directory. The permissions of the file itself are irrelevant
Since Windows is really the only system with delete access, and it already provides it's own accessor in the form of CreateFile with FILE_SHARE_DELETE, there really isn't a motivation to standardize this functionality.
If this functionality is pivotal to your program you could implement this cross-platform function (note that depending upon file size this could be very expensive):
Open file for read and write with an fstream; if this fails something else has a lock on the file and it would not be possible to open it for delete
Slurp the file
close the file
remove the file; if this fails you do not have delete permissions on the file
Reopen the file for writing with an ofstream
"Unslurp" the file into the ofstream
Return the ofstream
As long as the returned ofstream is open the operating system is responsible for preventing changes to the permissions on the file or it's containing directories. So by virtue of the fact that you have already deleted the file you know that you can still delete the file upon closing the ofstream.

ifstream not creating and opening a file for output

I am developing in C++ using NetBeans 6.9 on Ubuntu 11.04. I have declared the input and output file name strings and file streams thus
ifstream fpInputFile, fpOutputFile;
string inputFileName="", outputFileName="";
The input file name is assigned the name of an existing file as an input argument to the application. The output file name is given the same as the input name except that "_output" is inserted before the final period. So the output is written to the same directory as the input is located. Also I start netbeans with
su netbeans
so the IDE has root privileges to the directory. I try to open the files, and check whether they are opened thus.
fpInputFile.open(inputFileName.c_str(), ifstream::in);
fpOutputFile.open(outputFileName.c_str(), ifstream::out);
if (!(fpInputFile.is_open())) throw ERROR_OPENING_FILE;
if (!(fpOutputFile.is_open())) throw ERROR_OPENING_FILE;
The input file opens successfully but the output file does not.
Any help in determining why the output file is not opening for writing would be most appreciated.
Declare the output file as an ofstream rather than a ifstream.
You could also use a fstream for both input and output files.
The obvious problem is that you probably meant to open the file using a std::ofstream rather than an std::ifstream. This helps with actually writing to the stream although there are ways to write to an std::ifstream as long as it is opened for reading. For example, you could use the std::streambuf interface directly or use the std::streambuf to construct and std::ostream.
The more interesting question is: why isn't the file opened for writing when std::ios_base::in | std::ios_base::out is used for the open mode? std::ifstream automatically adds std::ios_base::in. It turns out, that the mode std::ios_base::in | std::ios_base::out doesn't create a file but it would successfully open an existing file. If you really want use an std::ifstream to open a file for output which potentially doesn't exist you would need to use either std::ios_base::out | std::ios_base::trunc or std::ios_base::out | std::ios_base::app:
the former would force the file to be created or truncated if it exists
the latter would force writes to append to the file in all cases
My personal guess is, however, that you are best off just using std::ofstream or, if you want to open the file for both reading and writing std::fstream (which, however, would also need to have std::ios_base::trunc or std::ios_base::app added to create a file if none exists).

c++ overwrite already opened file

I am opening a file with ifstream to check if it exists. Then I close it and open it with ofstream to write to it, and I think setting ios::trunc flag allows me to overwrite it.
However I'd like the ability to keep the file open if it exists, but I used an ifstream to open it so does that mean I can't write to the file till I close and re-open using fstream or ofstream? I didn't use fstream to begin with because that wouldn't tell me if the file was already there or not.
Just open a read-write fstream on the file. You can test if the file previously existed (and was non-empty) by seeking to the end and seeing if you're at a non-zero offset. If so, the file existed, and you can do whatever with it. If not, the file didn't exist or was empty. Assuming you don't need to distinguish between those two cases, you can then proceed as if it did not exist.
For example:
// Error checking omitted for expository purposes
std::fstream f("file.txt", std::ios::in | std::ios::out);
f.seekg(0, std::ios::end)
bool didFileExist = (f.tellg() > 0);
f.seekg(0, std::ios::beg);
// Now use the file in read-write mode. If didFileExist is true, then the
// file previously existed (and has not yet been modified)
The setting ios::trunc erases previous contents of the file.
Try opening the file without this setting; with only the 'write' setting.
this is touching very serios problem - race conditions - what if somebody manages to do something with this file between closing and reopening? unfortunately iostream does not provide any means of resolving that issue - you can use cstdio FILE. If you want to turncate file if exists or create new one if not use fopen(name, "w"). If you want to turncate file if it exists or fail otherwise, then it seems standard library has nothing to offer, and you should go to other libraries or platform specific functions like OpenFile in windows.h

c++ std::fstream behaviour on MacOS

On MacOS with gcc4.2 should the following code create a new file if none exists?
#include <fstream>
void test () {
std::fstream file ("myfile.txt", std::ios::in | std::ios::out);
}
By my logic it should, either open up an existing file for read/writing or create a new empty file for read/writing. But the behaviour I get is that it will not create a new file if 'myfile.txt' does not exist.
How do I get the same behavior as fopen("myfile.txt", "r+"); ?
Furthermore,
#include <fstream>
void test () {
std::ofstream file ("myfile.txt", std::ios::in | std::ios::out);
}
Will always truncate an existing file...
Is this the standard behavior?
First of all, I have no idea why you think that fopen("r+") creates a file if it doesn't exist - according to ISO C & C++, it does not, it just opens an existing file for read/write. If you want to create a file with fopen, you use "w+".
For streams, you just specify trunc:
std::ofstream file ("myfile.txt",
std::ios::in | std::ios::out | std::ios::trunc);
However, both this and fopen("w+") will truncate the file. There's no standard way to open the file without truncating if it exists, but create it if it does not exist in a single call. At best you can try to open, check for failure, and then try to create/truncate; but this may lead to a race condition if file is created by another process after the check but before truncation.
In POSIX, you can use open with O_CREAT and without O_TRUNC.
For the first case, you have specified that you are BOTH reading from and writing to the file. Hence, it will fail, if the file does not already exist. You could try to use two separate streams (one for reading and the other for writing), and construct the output stream, first. As for the second case, you can use "std::ios::app" (open in append mode) to prevent truncation. [Tested with Mac OS X 10.4.11, GCC 4.0.1]