Write to the middle of an existing binary file c++ - c++

I'm trying to open a binary file for writing without erasing the content. But I do not want to write to eof. I want to write to a specific position in file.
Here is a litte example:
ofstream out("test.txt", ios::binary | ios::app);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
out.close();
ofstream out2("test.txt", ios::binary | ios::app);
out2.seekp(10);
out2.write("Welt", 4);
out2.close();
If using app, seek doesn't work. If not using app opening file erases data. Does anybody know an answer?

try the second overload of seekp, which allows you to provide an offset and a direction, this could be begining of file in your case (i.e. ios_base::beg). This of course assumes you know what you are doing and all you want to do is overwrite an existing number of characters.
EDIT: here is fully working example:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
{
ofstream out("test.txt", ios::binary);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
}
{
fstream out2("test.txt", ios::binary | ios::out | ios::in);
out2.seekp(10, ios::beg);
out2.write("Welt", 4);
}
}

When opening with ios::app, it is as if you open a new file that just happened to be attached to an existing file: you can not access the existing file. I'm not sure, because I would do as in Kerrek's answer, but if you really want to try, you probably have to open with "ios::in | ios::out", similar to fopen("test.txt", "rw").
Or as crashmstr points out: ios::out might be enough.

You cannot magically extend the file from the middle. Perhaps easiest to write to a new file: First copy the initial segment, then write your new data, then copy the remaining segment. When all is done, you can overwrite the original file.

According to the specification of fstream here
fstream::open
the ios::app "Sets the stream's position indicator to the end of the stream before EACH output operation." So ios::app doesn't work for replacing, seeks of any sort fail, at least for me.
Just using ios::out does wipe out the file contents preserving only the size, basically turning the file into trash.
ios::in|ios::out turned out as the only working thing for me.

Working Code: This code searches for a string (OLD-STRING) in cout.exe and replaces with a new string (NEW-STRING).
`#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
fstream ifs;
ifs.open ("C:\\Users\\user\\Desktop\\cout.exe", fstream::binary | fstream::in | fstream::out);
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
size_t pos = str.find("OLD-STRING");
if (pos != string::npos)
{
cout << "string found at position: " << int(pos) << endl;
ifs.seekp(pos);
ifs.write("NEW-STRING", 10);
}
else
{
cout << "could not find string" << endl;
}
if (ifs.is_open())
ifs.close();
return 0;
}`

Related

C++ fstream writes garbage to file

The code below creates a vector that contains a vector of chars. It opens a fstream to a file. and then write the first char from the first vector. I tried to methods to write the char. Finally, I tried open a new 'fstream' and from it to print what I wrote. Both the printing and a simple inspection of the file shows it contian nothing, or sometimes garbage (dependening on the order of the writes). No errors or any weried output appear. I'm really loosing my mind over this.
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
std::vector<char> y(6, 0);
y[0] = 1;
std::vector<std::vector<char>> vy;
vy.push_back(y);
std::fstream dateir("ffff.dat", std::ios::out | std::ios::out | std::ios::binary);
dateir<<vy[0][0] << endl;
int temp = vy[0][0];
dateir.write((char *)&temp, sizeof(int));
dateir.close();
cout << "here" << endl;
std::ifstream dateir2("ffff.dat", std::ios::out | std::ios::out | std::ios::binary);
if (dateir2.is_open())
{
std::cout << dateir2.rdbuf();
}
else{
cout << "no";
}
dateir2.close();
cout << "end";
return 0;
}
You have...a number of problems here.
std::fstream dateir("ffff.dat", std::ios::out | std::ios::out | std::ios::binary);
Is there a reason you've specified std::ios::out | std::ios::out? It's harmless, but clearly redundant.
As a first stab at things, I'd simplify the code a bit:
std::ofstream out("ffff.dat", std::ios::binary);
int data = 1;
out.write((char *)&data, sizeof(data));
out.close();
std::ifstream in("ffff.dat", std::ios::binary);
int data2;
in.read((char *)&data2, sizeof(data2));
if (data == data2) {
// what we read matched what we wrote
} else {
// what we read didn't match what we wrote
}
When you write binary data to a file, you usually want to just read it back in the way you wrote it out. If you want to look at the individual characters, you can do that but to get something that's semi-readable, you probably want to print them out in hexadecimal, or something on that order (and for this sort of exercise to mean much, you'd probably want to print it out in hex both before writing it out, and after reading it back in, to show they match, and let the reader see a reasonable understandable representation of the file contents).

How to read in binary mode and transfer the information to new file

i tried to open and read an application in binary mode and get 100 characters(For a large file, i did this so that i could read all the characters) in binary mode and then transfer them to new file(in fact, this program will be the same as the previous program, but with a different name ) to find out if it works properly or not
so anyway my source code is:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
//Vector of 100 characters initialised to 0
vector<char> ch(100, 0);
ifstream file("example.exe",ios::in|ios::binary);
if (file.is_open())
{
while (file)
{
file.read(ch.data(), 100);
// Get the number of bytes actually read
size_t count = file.gcount();
ch[file.gcount()] = '\0';
//cout << ch.data() << endl;
ofstream output("output.exe", ios::out | ios::binary | ios::app);
output.write(ch.data(), sizeof(100));
output.close();
}
}
file.close();
}
my problem is the output with the correct information is not included and the size is smaller than the original application(example.exe) what is happening?
The line output.write(ch.data(), sizeof(100));
should be replaced with output.write(ch.data(), count);
Since sizeof(100) only returns 4, which is the size in bytes of an integer.
You should also remove the line ch[file.gcount()] = '\0'; since file.gcount() might be out of bound.
I just tested it and this works for me
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
vector<char> ch(100, 0);
ifstream file("app.exe",ios::in|ios::binary);
if (file.is_open())
{
ofstream output("app_copy.exe", ios::out | ios::binary | ios::trunc);
while (file)
{
file.read(ch.data(), 100);
output.write(ch.data(), file.gcount());
}
output.close();
}
file.close();
}
Notice that ios::app is replaced by ios::trunc, which will delete the content of the file when opening.

Trying to read binary file clears the file itself

I just started working with binary files in C++, and i have successfully written and read a (.bin) file. Here is the code:
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main()
{
char input[100];
strcpy(input, "This is a string");
fstream file("example.bin", ios::binary | ios::in | ios::out |
ios::trunc);
if(!file.is_open())
{
cerr << "Error opening file.\n";
} else {
for(int i = 0; i<= strlen(input); i++)
{
file.put(input[i]);
}
}
file.seekg(0);
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
}
And this worked. After that, i tried to redesign the code to just read a binary file. The major changes were: changed fstream to be an ifstream(to read), deleted the part with writing into a file. Once the code was ready, i found a file i want to read (eof0.bin). When i used the code, the only thing i got was an empty string. I noticed that the initial size of the file was 37 kilobytes, while after using my program it became 0. I want to know, how my program cleared the data in the binary file?
This is the code that i used to read the file.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main()
{
ifstream file("eof0.bin", ios::binary | ios::in | ios::out | ios::trunc);
if(!file.is_open())
{
cerr << "Error opening file.\n";
} else {
// Nothing.
}
file.seekg(0);
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
}
Everything compiles, but using it on a file 37 kilobytes in size gives me a 0 kilobyte file.
You open with an openmode std::ios_base::trunc. From http://en.cppreference.com/w/cpp/io/ios_base/openmode we can see that it
discard[s] the contents of the stream when opening
So just use:
// also dropped ios::out since you only want to read, not write
ifstream file("eof0.bin", ios::binary | ios::in);
Further, this
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
is not an appropriate way to read the file. Think about what happens with an empty file: After opening it, it's "good" (remember, the eofbit is only set when some input operation encounters eof). Then the get fails, leaving ch as it is, thus invoking undefined behavior. Better test on the stream state directly after the input operation:
char ch;
while (file.get(ch)) {
// use ch
}
// optionally distinguish eof and fail cases
For more background on reading files, see Why is iostream::eof inside a loop condition considered wrong?

Access of file on desktop using C++

I am using Windows 7 and I have created on the desktop a file named test.txt. How can I access this file using C++? For example, consider following code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
fstream inout("test.txt", ios::in | ios::out | ios::binary);
if(!inout) {
cout << "Cannot open input file.\n";
return 1;
}
long e, i, j;
char c1, c2;
e = 5;
for(i=0, j=e; i<j; i++, j--) {
inout.seekg(i, ios::beg);
inout.get(c1);
inout.seekg(j, ios::beg);
inout.get(c2);
inout.seekp(i, ios::beg);
inout.put(c2);
inout.seekp(j, ios::beg);
inout.put(c1);
}
inout.close();
return 0;
}
In the fragment fstream inout("test.txt", ios::in | ios::out | ios::binary), what should I change to access my test.txt on desktop?
Are you asking how to access that file location from your program? If so, you need to put the file and the executable in the same directory, or include a full path to the file's location:
"%USERPROFILE%\\Desktop\\test.txt"
Unless there is a full file path starting from a drive letter (the variable %USERPROFILE% evaluates to C:\Users\ {your username} in your case) the executable will look for the file relative to its own location. Since your string contains only the file name, it will look in its own directory.
You need to provide the full path to the file. Determine what the absolute path is for the file and use that in the first argument:
fstream inout("c:\\some\\whole\\path\\to\\docmument\\test.txt", ios::in | ios::out | ios::binary);
Easiest way is to use ifstream, that is
ifstream inputfile("\path\to\input\file);
What path it is is easiest seen using your explorer or whatever it is called these days.
I would try to provide the abosolute path to test.text, which can be something like (I'm not sure):
C:\WINDOWS\Desktop\test.txt
The path to the desktop is available
#include <shlobj_core.h>
ofstream file;
TCHAR appData[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE,
NULL,
SHGFP_TYPE_CURRENT,
appData)))
{
int Size = 0;
string pathDesktop;
while (appData[Size] != '\0') pathDesktop+= appData[Size++];
pathDesktop+= "\\test.txt";
file.open(pathDesktop);
if (file.is_open())
{
file << "Hello World";
file.close();
}
}

Why can't I read and append with std::fstream on Mac OS X?

Consider the following C++ program, which takes a file and prints each line. It's a slice of a larger program where I later append to the file, based on what I see.
#include <fstream>
using std::fstream;
#include <iostream>
#include <string>
using std::string;
int main()
{
fstream file("file.txt", fstream::in | fstream::out | fstream::app);
string line;
while (std::getline(file, line))
std::cerr << line << std::endl;
return 0;
}
Now apply this version of file.txt (One word on the first line, followed by a newline):
Rain
On my machine (Snow Leopard), this prints out nothing. On closer inspection, the first call to getline fails. Strangely, it also fails if I add a second line: still nothing is printed!
Can anyone solve this mystery?
When you say:
fstream file("file.txt", fstream::in | fstream::out | fstream::app);
you open the file in append mode - i.e. at the end. Just open it in read mode:
fstream file("file.txt", fstream::in );
or use an ifstream:
ifstream file("file.txt" );
And of course as Earwicker suggests, you should always test that the open succeeded.
If you are determined to open in append mode, you can move the read pointer explicitly:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
fstream file( "afile.txt", ios::in | ios::out | ios::app );
if ( ! file.is_open() ) {
cerr << "open failed" << endl;
return 1;
}
else {
file.seekg( 0, ios::beg ); // move read pointer
string line;
while( getline( file, line ) ) {
cout << line << endl;
}
}
}
Edit: It seems that the combination of flags used in the opening of the file leads to implementation specific behaviour. The above code works with g++ on Windows, but not with g++ on Linux.
You should check if the file has actually been opened:
if (!file)
std::cerr << "Oh dear" << std::endl;
Update: in fact the file likely has been opened, but is in append mode - see Neii's answer.
Update 2: okay, wrong again. In Leopard's g++ at least, the file will not be opened because the app flag is incompatible with the in flag. So the above check will print Oh dear.
In MSVC++, it goes ahead and opens the file, apparently with the read position at the start, which explains why other people saw it work and I apologise for doubting their veracity!