C++ replace data in binary file with fstream - c++

I try to replace data in binary file using C++ and fstream library. Is it possible to do that with this library?
I would like to change one byte of file in address: 0xB07 to 1.
I have written the following code snippet:
...
int address = 0xB07;
char * toChange = new char('0');
std::ifstream input(filename, std::ios::binary);
input.seekg(address);
input.read(toChange, 1);
input.close();
*toChange = (char)0x01;
std::ofstream output(filename, std::ios::binary);
output.seekp(address);
output.write(toChange, 1);
output.close();
...
I have tried many versions of this code and I still can't understand why the byte doesn't change.

This code will remove your file and put totally new contents in it.
The problem is in line
std::ofstream output(filename, std::ios::binary);
That's because the default open mode is ios::out | ios::trunc (See for ex.: Input/Output with files)
Which means file is being truncated to zero bytes.
Then your seek() function extends him to the specified size (usually filling with zeroes) and finally output.write() writes the byte at the end.
In order to do what you want I had to specify the following ofstream flags: std::ios::binary|std::ios::out|std::ios::in
I cannot say currently for sure why the std::ios::inis needed, sorry...

Related

writing buffer to ofstream causes tellp() to point to the end of file

After calling seekp() to the middle of file, then writing my buffer, the file-pointer teleports to the end of file.
My code is more complex but essentially comes down to the following:
std::lock_guard<std::mutex> lckFile(_mu_fileAccess);
const char* buff = new const char[200];
int preallocSize = 1024*512;
_f.open(path_file_with_exten, std::ios::app | std::ios::binary );
if(!_f){
delete[] buff;
return;
}
std::experimental::filesystem::resize_file(path_with_exten, preallocSize);
_f.seekp(321, std::ios_base::beg);
int64_t currPos = _f.tellp(); //will be 321
_f.write(buff, 100);
_f.tellp(); //somehow is equal to 1024*512 instead of 321+100
What might be causing this behavior? It occurs only in one specific place of my code. Other invocations of this code from other places work ok and don't teleport the pointer that far away.
I'm using C++14
Edit:
Following the below answer, I had to use std::ios::ate not std::ios::app.
However, I discovered that my file started to be re-created from scratch even though I'm not specifying std::ios::trunc.
I had to pass in additional flag in to make sure the file contents are preserved:
auto flags = std::ios::ate | std::ios::in | std::ios::out | std::ios::binary; _f.open("myFile.exten", flags);
otherwise documentation says "Creating a file. If the file already exists, the old version
is deleted."
From my comment above.
Documentation for open modes
app: seek to the end of stream before each write
Thus :
_f.write(buff, 100);
…triggers a seek to the end of the file before writing.

Opening a file to read and write, create it if it doesn't exist

I was trying to create a file in both read and write modes, but it doesn't create the file, what can be the problem?
This is code:
fstream file("NameFile.txt", ios::out| ios::in);
The program will start, but it will not create any files.
When you open the file using fstream:
To read, the file is required to exist;
To write you need to specify a write mode, ofstream would do that for you, but with fstream you need to do it yourself:
Replaces the contents of the file when you write (ofstream default mode).
std::fstream file("NameFile.txt", std::ios::out | std::ios::in | std::ios::trunc);
^^^^^^^^^^^^^^^
Appends to the existing data in the file when you write.
std::fstream file("NameFile.txt", std::ios::out | std::ios::in | std::ios::app);
^^^^^^^^^^^^^
Note that after reading or writing you'll need to set the offset position in the file, for instance:
std::string s = "my string";
std::string in;
file << s;
file >> in;
file >> in will not read anything, the position indicator is at the end of the file after file << s, you'll need to reset it if you want to read previously written data, for example:
file << s;
file.seekg(0);
file >> in;
This resets the read position indicator to the beggining of the file, before the file is read from, more about it here:
https://en.cppreference.com/w/cpp/io/basic_fstream
well, you initialized an object, now to create a file use
file.open();
see
fstream won't create a file

Reading/Writnig BSON file

I am using the https://github.com/nlohmann/json libary for writing out my object to BSON. I have validated creating the json instance by writing the file out to json for review, so that portion of the code is working as expected. I am having issues with it once I swap back to bson though.
Here is the snippet of code I am working with:
//I have written out json_triangle_container to verify it looks correct
//so I am sure the problem is not here
json json_instance = <my function to create this instance>
std::vector<std::uint8_t> v_bson = json::to_bson(json_instance);
//writing the vector out here
auto bsonFilename = std::string("json_instance.bson");
std::ofstream bsonfile(bsonFilename, std::ios::out | std::ios::binary);
bsonfile.write((char*)&v_bson[0], v_bson.size() * sizeof(v_bson[0]));
bsonfile.close();
//reading it back in here
std::ifstream r_file(bsonFilename, std::ios::in | std::ios::binary | std::ios::ate);
std::streampos size = r_file.tellg();
r_file.seekg(0, std::ios::beg);
char* memblock = new char[size];
r_file.read(memblock, size);
r_file.close();
//printing out the json object for testing
auto json_instance_read = json::from_bson(memblock); //this is where it is blowing up
std::cout << json_instance_read << std::endl;
I get an exception that says:
Exception thrown at 0x00007FFF4EE6A839 in test.exe: Microsoft C++ exception: nlohmann::detail::parse_error at memory location 0x0000006AB4D5F470.
It is also worth noting if I call json::from_bson(v_bson ) it parses fine. I validated the array size being read in is the same size as the vector I wrote out. So this is leading me to believe I did something wrong in how I wrote the bson out initially.
Edit
Using some online tools to convert the bson file I generated to json it seems the writing is correct. So that points to my read function being the issue.
Doing some more debugging, it looks like in the v_bson vector the 3 item has the value '\0' which I think is throwing off the reader and it is stopping short before reading the entire file. I confirmed this by checking the size of the memblock and it is only 3 characters long.
So the question changes a bit:
How do I tell ifstream reader to ignore what it seem to think is an EOF character?
Everything I have found says to make sure to initialize it with std::ios::binary, which I do:
std::ifstream r_file(bsonFilename, std::ios::in | std::ios::binary | std::ios::ate);

How can I open a file in c++, without erasing its contents and not append it?

I am trying to find a way using which I can Edit the contents in a binary file, without reading the whole file.
Suppose this is my file
abdde
And I want to make it
abcde
I tried following:-
Attempt 1)
ofstream f("binfile", ios::binary);
if(f.is_open()){
char d[]={'c'};
f.seekp(2,ios::beg);
f.write(d, 1);
f.close();
}
//the file get erased
Output:
**c
Attempt 2)
ofstream f("binfile", ios::binary | ios::app);
if(f.is_open()){
char d[]={'c'};
f.seekp(2,ios::beg);
f.write(d, 1);
f.close();
}
//the file simple gets append seekp() does nothing
Output:
abddec
Attempt 3)
ofstream f("binfile", ios::binary | ios::app);
if(f.is_open()){
char d[]={'c'};
f.seekp(2);
f.write(d, 1);
f.close();
}
//same as before the file simple gets append seekp() does nothing
Output:
abddec
And if I just try to replace the 1st byte of the file, which is 'a' with 'h'
ofstream f("binfile", ios::binary);
if(f.is_open()){
char d[]={'c'};
f.seekp(ios::beg);
f.write(d, 1);
f.close();
}
//file is erased
Output:
h
What do I do? Is it even possible for the OS to allow a program to edit a file at any point own its own?
std::ios::app means the cursor is put at the end of the file before every write. Seeking has no effect.
Meanwhile, std::ios::binary goes into "truncation" mode by default for an output stream.
You want neither of those.
I suggest std::ios::out | std::ios::in, perhaps by just creating a std::fstream fs(path, std::ios::binary) rather than using an std::ofstream.
Yes, it's a bit confusing.
(Reference)

overwriting some text in a file using fstream and delete the rest of the file

I am trying to write a program that read a file using fstream
then, rewrite some of the text and delete the rest of the file
This the code that I am trying to do
#include<iostream>
#include<fstream>
using namespace std;
int main(int argc, char **argv){
fstream *binf;
fstream someFile("t.txt", ios::binary|ios::out|ios::in);
int i;
for(i=0;i<3;i++){
char c;
someFile.seekg(i);
someFile.get(c);
cout<<"c:"<<c<<endl;
}
someFile.seekp(i++);
someFile.put("Y");
someFile.seekp(i++);
someFile.put("Y");
//Delete the rest of the file
return 0;
}
Note the following flags for opening a file
ios::in Open for input operations.
ios::out Open for output operations.
ios::binary Open in binary mode.
ios::ate Set the initial position at the end of the file. If this flag is not set to any value, the initial position is the beginning of the file.
ios::app All output operations are performed at the end of the file, appending the content to the current content of the file. This flag can only be used in streams open for output-only operations.
ios::trunc If the file opened for output operations already existed before, its previous content is deleted and replaced by the new one.
I try many combinations of these but non of them help me to do what I want
I want to read the file until I find text. If I find the text that I want, I over write it and delete the rest of the file. So, the file should be re-sized to smaller file.
You can't do that with single stream object.
Possible solutions:
Either close your file and call truncate function, :
#include <unistd.h>
int ftruncate(int fildes, off_t length);
int truncate(const char *path, off_t length);
MS Windows version of truncate is _chsize - see http://msdn.microsoft.com/en-us//library/dk925tyb.aspx
int _chsize(
int fd,
long size
);
Or open your file for reading only, read/replace to some stringstream, then put everything to your file this time opened for overwriting:
fstream someFile("t.txt", ios::binary|ios::in);
stringstream ss;
// copy (with replacing) whatever needed from someFile to ss
someFile.close();
someFile.open("t.txt", ios::binary|ios::out|ios::trunc);
someFile << ss.rdbuf();
someFile.close();