C++ Seekp() in binary files is removing the data - c++

I want to use seekp() function with binary files to modify the data of certain integer. I have made simple test program to test seekp funstion but it does not work rather it deletes the old content in file.
// position in output stream
#include <fstream> // std::ofstream
#include <iostream>
int main() {
std::ofstream outfile{"test.dat" ,std::ios::binary| std::ios::out};
struct t {
int x;
};
t t1{ 36};
t t2{ 2 };
t t3{ 3 };
outfile.seekp(4 , std::ios::beg );
outfile.write((char*)&t1 , sizeof(t1));
outfile.write((char*)&t2, sizeof(t2));
outfile.write((char*)&t3, sizeof(t3));
outfile.close();
std::ifstream iutfile{ "test.dat" ,std::ios::binary };
t read;
while (iutfile.read((char*)&read, sizeof(read)))
{
std::cout << "\n\n\t" << read.x;
}
iutfile.close();
return 0;
}
#here are my steps i am doing to test it:#
1)comment the outfile.seekp(4 , std::ios::beg ); in code above then it will print the contents in file
2)now uncomment the seekp line and comment the two outfile.write() lines leaving one to test whetehr seekp is putting the pointer so i can write at exact loaction But when i do this the previous data lost
3)i then tried commenting all write lines leaving seekp lines uncommented and then i saw the whole file cintent is removed
WHat i am doing wrong i cant understand . I have tried seekp(sizeof(int) , std::ios::beg) but it also doest not work .. Any help please

You destroy content of file every time you open it, it has nothing to do with seekp.
std::ios::out means implicitly std::ios::trunc, unless there is std::ios::in or std::ios::app as well (yes, it's a mess). See cppreference for detailed description of how flags work with each other.
You need to open file in append mode and then seekp to position that interests you:
std::ofstream outfile{"test.dat" ,std::ios::binary | std::ios::app}; //out is optional
std::ofstream outfile{"test.dat" ,std::ios::binary | std::ios::app | std::ios::out};

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.

fstream seekp() not working when the file is opened in ios::in and out mode

I want to replace some certain portion (in the middle) in a binary file. If I use ostream out("file.bin",ios::binary) ,it will delete the old file and creat a new one. But if I use fstream out("file.bin",ios::binary|ios::in|ios::out) ,seekp() will not go to the right place and tellp() always return -1. So is there any way to replace some certain portion in a file?
Thank you in advance.
You must open the stream with the at the end, in and out bits set:
std::fstream out("file.bin", ios::binary | ios_base::ate);
This will prevent your file to be reset at opening; then, using seekp and unformatted output functions you will be able to edit it in the middle.
This example outputs stackovstrlow, showing how to chain all steps together:
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
int main()
{
// create the bin file
{
std::string str("stackoverflow\n");
std::ofstream file("file.bin", std::ios_base::binary);
file.write(str.c_str(), str.length() + 1);
}
// edit the bin file "in the middle"
{
std::fstream file("file.bin", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
file.seekp(7);
file.write("str", 3);
}
// read and see what we've done
std::ifstream file("file.bin", std::ios_base::binary);
std::vector<char> v(14);
file.read(v.data(), 14);
std::string str(v.cbegin(), v.cend());
std::cout << str;
}
Seeking on file streams is supposed to work although not always. Notably, seeking does fail if the encoding used by the imbue()ed std::locale() is variable width. Quoting from 27.9.1.5 [filebuf.virtuals] paragraph 13:
Effects: Let width denote a_codecvt.encoding(). If is_open() == false, or off != 0 && width <= 0, then the positioning operation fails. ...
Assuming the file was opened OK, it would imply a std::locale with a non-fixed width encoding was used. The approach to avoid this issue is to use the C-locale before opening the file. For example:
std::fstream stream;
stream.imbue(std::locale::classic());
stream.open("file.bin", std::ios_base::binary | std::ios_base::in | std::ios_base::out);

Input Output with fstream

Can anyone tell me what is wrong with this code? I always get not open.
#include <iostream>
#include <fstream>
using namespace std;
int main(){
fstream fs;
fs.open("fsfile2",ios::in|ios::out|ios::binary);
if(fs.is_open()){
fs.write("wow",sizeof("wow"));
char str[20];
fs.read((char*)str,sizeof(str));
cout<<str<<endl;}
else
cout<<"Not open\n";
return 0;
}
Try this code
fs.open("fsfile2", ios::app|ios::in|ios::out|ios::binary);
By using the open() like you are that file will not be created if that is your goal.
If you want to create a new file please look at: fstream won't create a file
If the file exists, you are not looking for it in the right path. Or change the file name to the full path or put the executable in the folder where the file is.
Hope this helps.
Probably, you do not have permissions to create files in the directory, where your executable is.
Solution:
Please add a file extension to the filename.
If it's a text file, it will be
"fsfile2.txt"
Then, I tried removing
ios::in
since the first process only writes to file, and by removing that, the file is created and "wow" is also written at it.
In order for these lines
fs.read((char*)str,sizeof(str));
cout<<str<<endl;
to work,
You need to close the stream after writing to it, then open the stream in read mode, then read the contents. Take note that closing the stream will save the edited file.
Additional:
You can also change
fs.write("wow",sizeof("wow"));
to
fs << "wow";
You can do the same when reading from file,
fs >> str;
You can also use the string class of C++, instead of char array so that the number of characters inside the file won't be your problem anymore.
#include <string>
string str;
Checking for EOF (end-of-file) is recommended since files are read line by line. Once you add a new line and add a character to the line, the code that doesn't loop until EOF will only read the first line of the file.
In order to solve this, it is recommended to loop until EOF is reached.
while(!fs.eof()) {
fs >> str;
cout << str << endl;
}
So here is the improved snippet:
#include <string>
fs.open("fsfile2.txt", ios::out); // ios::out for write only
if(fs.is_open()) {
// writes "wow" to file
fs << "wow";
// closes the file
fs.close();
// ios::in for read only
fs.open("fsfile2.txt", ios::in);
// better to define variable just before using it
string str;
// loops until end-of-file
while(!fs.eof()) {
// reads a line from file, stores it to str
fs >> str;
// shows str to screen
cout << str << endl;
}
}
*Note: I removed
ios::binary
Since your code is not dealing with binary files yet.
I tried these and it worked fine! Have a nice day!
fstream fs; does not create a new file for you.
You need to make sure that the file exists in your project directory.
On the other hand, if you were to use ofstream fs("file.txt"); it would create the file for you. Or use only ios::out when you open fstream fs, this will create the file for you.

read and write a binary file in c++ with fstream

I'm trying to write simple c++ code to read and write a file.
The problem is my output file is smaller than the original file, and I'm stuck finding the cause.
I have a image with 6.6 kb and my output image is about 6.4 kb
#include <iostream>
#include <fstream>
using namespace std;
ofstream myOutpue;
ifstream mySource;
int main()
{
mySource.open("im1.jpg", ios_base::binary);
myOutpue.open("im2.jpg", ios_base::out);
char buffer;
if (mySource.is_open())
{
while (!mySource.eof())
{
mySource >> buffer;
myOutpue << buffer;
}
}
mySource.close();
myOutpue.close();
return 1;
}
Why not just:
#include <fstream>
int main()
{
std::ifstream mySource("im1.jpg", std::ios::binary);
std::ofstream myOutpue("im2.jpg", std::ios::binary);
myOutpue << mySource.rdbuf();
}
Or, less chattily:
int main()
{
std::ofstream("im2.jpg", std::ios::binary)
<< std::ifstream("im1.jpg", std::ios::binary).rdbuf();
}
Two things: You forget to open the output in binary mode, and you can't use the input/output operator >> and << for binary data, except if you use the output operator to write the input-streams basic_streambuf (which you can get using rdbuf).
For input use read and for output use write.
There are 3 problems in your code:
1- You have not opened your output file in Binary.
2- Your code return "1", normally you should return "0", if something went wrong then return an error code.
3- You should use "manipulators" and make c++ not to avoid whitespaces, so in order to read from file instead of:
mySource >> buffer;
you should use:
mySource >> std:noskipws >> buffer;
Well, its just because of padding at the end of the image. eof of any file do not include the padded bytes added at the end of file.
Try this
take img1.jpg contains 20 space charecter at the end not visible here (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf ) and run your program (do not include parenthesis in the file, these are used to show the data content)
you will see img2.jpg contains (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf)
So, its better option to read the file byte by byte using the filesize which you can get using stat, and run for loop till filesize. Hope this should resolve your problem you mentioned above

Why doesn't this program read (or write?) correctly from a .bin file? (C++)

I created this program:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream file;
file.open("test.bin", ios::in | ios::out | ios::binary);
if(!file.is_open())
{
return -1;
}
int n = 5;
int x;
file.write(reinterpret_cast<char*>(&n), sizeof(n));
file.read(reinterpret_cast<char*>(&x), sizeof(x));
std::cout<<x;
file.close();
std::cin.ignore();
return 0;
}
that's supposed to write an integer "n" into a .bin file "test.bin", then read data from "test.bin" into an integer "x", then displays "x" to the screen.
When I run the program, it displays not 5, but -842150451. Why does this occur, and how can I fix it?
Isn't the file.write() moving the current file pointer when you write it, causing you to read data from the first location AFTER the written data?
Insert file.seekg(0); between the read and write commands.
You have to reposition the file stream to the start of the file after you do the write in order to read the data you just wrote.
You should also check that the write wrote everything you expected it to, and whether the read actually read anything at all. The semi-random number is due to the read failing.
I agree with Jherico. You need a:
file.seekg (0, ios::beg);