c++ overwrite already opened file - c++

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

Related

c++ filestream problems when opening file in read write mode

Consider the following code snippet:
const char * filePath = "C:/blah.mtt";
fstream fs(filePath, ios::in | ios::out | ios::binary);
if (fs.fail())
std::cout << "Failed to open the file!\n";
the fs.fail() check succeeds always. Does it mean that I can't open a file in both read write mode at the same time?
Creating an empty file first and then running the above code, fs.fail() is false always. What is the rational for such a behavior by the fstream class?
Note: I do have requisite permissions for creating the file. I am trying this on windows 10 using VS2015
Does it mean that I can't open a file in both read write mode at the same time?
No, you can do this, but the question is whether you can create a file by doing so.
Generally you'll need to add the trunc flag (ironically one of the options for how to handle an existing file), or remove the in flag (see here).
Yes, this is a bit of a pain, but it comes from how the original POSIX APIs work. Blame them!
Creating an empty file first and then running the above code, fs.fail() is false always. What is the rational for such a behavior by the fstream class?
You can always open a file that exists (well, subject to permissions). That behaviour makes sense.
the fs.fail() check succeeds always. Does it mean that I can't open a file in both read write mode at the same time?
Refer to #Lightness Races in Orbit's answer for a better explanation.
Creating an empty file first and then running the above code, fs.fail() is false always. What is the rational for such a behavior by the fstream class?
If you look at the constructor definition of fstream you can see that mode defines the way you open it. It has other options like app to append to an existing file. If you open up a file using the following code:
fstream fs(filePath, ios::in | ios::out | ios::binary);
You are saying create a new file if it doesn't exist. Which fails if you pre-created it. You should add the app, ate or truncflag if you want it to open successfully. This depends on what exactly you want to do. However, do note that in between the steps of creating and then opening it doesn't guarantee that the file is still there. You should try to do it in one swoop and let exception handling do its work, since you can never go around the errors anyway.

std::ofstream open file and replace in specific offset

I want to open a file (without re-creating it) and write to a specific offset.
This is the current code :
std::ofstream file(conf_file_path, std::ios::app);
file.seekp(offset, std::ios::beg);
const auto& output = file.write(conf_str, conf_str_len);
But it always writes to the end of file (probably due to the app flag)
If I don't use the app flag, it re-creates the file as I open it.
How can I open it without re-create it and be able to write to specific offset ?
it always writes to the end of file (probably due to the app flag)
Yes, this is due to the app flag. Here's what the documentation says:
app - seek to the end of stream before each write
If I don't use the app flag, it re-creates the file as I open it.
If you have out or trunc flags sets in the mode, then it destroys the contents of the file, if it already exists.
How can I open it without re-create it and be able to write to specific offset ?
You may use in|out. This will error out if the file doesn't exist; if it exists, the file will be opened and read from the beginning. If you want the stream to be read from the end, you may set the ate flag additionally.
All of this is clearly documented here; reading the manual really helps.

C++ ofstream equivalent to Win32 CreateFile with CREATE_NEW

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).

How to clear a file in append mode in C++

I've a file on which I require multiple operations. Sometimes I just want to append data at the end of the file, sometimes I just want to read from the file, and sometimes, I want to erase all the data and write form the beginning of the file. And then, I again need to append data at the end of file.
I'm using following code:
ofstream writeToTempFile;
ifstream readFromTempFile;
writeToTempFile.open("tempFile.txt", ios::app | ios::out);
readFromTempFile.open("tempFile.txt", ios::in);
// Reading and Appending data to the file
// Now it is time to erase all the previous data and start writing from the beginning
writeToTempFile.open("tempFile.txt", std::ofstream::trunc); // Here I'm removing the contents.
// Write some data to the file
writeToTempFile.open("tempFile.txt", std::ofstream::app); // Using this, I'm again having my file in append mode
But what I've done doesn't work correctly. Please suggest me some solution in C++. ( Not in C)
The problem with the code is:
I wasn't closing the file before I called the method open again on it.
So, close the file before you re-open it with some different permissions.

fstream replace portion of a file

When I do
fstream someFile("something.dat", ios::binary|ios::out);
someFile.seekp(someLocation, ios::beg);
someFile.write(someData, 100);
It seems to replace the entire file with those 100 bytes instead of replacing only the appropriate 100 bytes, as if I had specified ios::trunc. Is there a portable way to not have it truncate the file?
Edit: adding ios::in seems to do the trick, by why is this required, and is that standard behavior?
Edit #2: I am not trying to append to the existing file. I need to replace the 100 bytes while leaving the rest unaffected.
You want the append flag, ios::app, if you want to write at the end of the file.
To do it somewhere arbitrarily in the middle of the file, you need to seek to the right place. You CAN do this by opening the file for in and out, but if I were you I'd create a temp file, copy input up to mark, write your new data, copy the rest to EOF, close the files and replace the previous version with the temp file. This is called a "Master File update".
AFAIR ios::out only specifies the file is for output and ios:binary only specifies the files is binary. The default behaviour for a stream is to create a new file and overwrite the old file. If you want to modify an existing file you must open the file with the ios::app flag.
ATM I cannot check my references so be sure to double check, but I felieve that is accurate.
Since the file already exists open it in 'read+write' mode and then do seekp. I think it will work.
fstream someFile("something.dat", ios::binary|ios::out|ios::in);
someFile.seekp(someLocation, ios::beg);
someFile.write(someData, 100);
The ios:in mask tells the file pointer to position at the beginning of the file so it can start reading in from the start. But, you may want to use fseek to set the file pointer at the beginning of the file.