C++ Can't write file with peek ; using fstream - c++

I create in C++ a function that write in file, by using stream. I want that file was overwrite when i call this code. When i add a fstream.peak, to know the next char, nothing was written in my text file. If they return -1, I want they write at X position in my text file. Here's my code (note that I begin in C++..) Thanks for the future help! :)
fstream myFStream = myFStream.open("./myFile.txt, ios::in |ios::out | ios::trunc | ios::binary);
int positionFile = 2;
myFStream.seekp(positionFile, ios::beg);
char textToWrite[10] = "";
textToWrite = "mytext";
**// [don't write when I add this IF]
if (myFStream.peek() > 0)
{ positionFile += 15; }**
myFStream.write(textToWrite, 6);
myFStream.close();

Related

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)

Can insert in an fstream, but not in an iostream

Trying to insert a string in the middle of a file, starting from its end.
The following code works with an fstream, but not with an iostream (in this case the output string is equal to the input one):
// File contents: "abcdefghijklmnopqrstxyz"; "uvw" missing
// 1 - OK
//fstream iofs(fPath, ios_base::in | ios_base::out);
// 2 - Same output
filebuf fileBuffer;
iostream iofs(&fileBuffer); // generic output stream
fileBuffer.open(fPath.c_str(), ios_base::in | ios_base::out | ofstream::app);
iofs.rdbuf(&fileBuffer);
iofs.seekg(0, ios_base::end);
iofs.seekp(0, ios_base::end);
for(int i = 1; i < 20; ++i)
{
iofs.seekg(-i, std::ios_base::end);
char c = char(iofs.peek());
if(c == 't') {
iofs.seekp(-i + 1, std::ios_base::end);
iofs << "uvw"; // add missing token
iofs << "xyz"; // append pre-existing token
break;
}
}
Output:
Case 1: Begin = abcdefghijklmnopqrstxyz; Result = abcdefghijklmnopqrstuvwxyz
Case 2: Begin = abcdefghijklmnopqrstxyz; Result = abcdefghijklmnopqrstxyz
Am I doing something wrong, or I simply cannot do an insert in a iostream?
A generic iostream is not seekable - think keyboard or printer.
You don't check the result of the seekp operation. It probably fails and sets the stream into an error state. Any further output attempts will then do nothing.

Can't append text to specific position in C++

I'm trying to add text to a specific position in C++ with ofstream and seekp. However, it always append to the end of the file.
I've alredy tried to write with file.write(string, len), but the result is so the same.
My code:
void printHistory(int media, time_t timestamp){
ofstream file("history.json", ios::app);
long initial_pos = file.tellp();
file.seekp(initial_pos-3);
file << ", [" << timestamp << "," << media << "]]\n}";
file.close();
}
How about something like:
fstream fs ("fred.txt", ios::in | ios::out);
fs.seekg (0, ios::end);
streamoff filesize = fs.tellg();
fs.seekp (filesize - 3); // locate yourself 3rd char from end.
fs.write( "X", 1 );
fs.close();
Generally, to "insert" you have to write to a temporary stream or file. You cannot actively update in the middle.
Lots of STL types support insertion, but it is simulated via behind the scenes processes.
pseudo code:
pos = some_int_point_in_file
open(file) as f and open(tmp) as t:
read f into t until pos then
insert whatever
finishing reading the rest of f into t
swap file and tmp

need help converting c to c++ (simple error but cant fix)

I have a c++ homework. The homework is asking to convert a c program to c++.
Below is the question:
You are requested to convert the following C function into a C++
function and then embed it into a complete program and test it. Note
that this function copies a binary file of integers and not a text
file. The program must accept the arguments (the file to copy and the
file to be copied to) from the command line.
/* ==================== cpyFile =====================
This function copies the contents of a binary file
of integers to a second file.
Pre fp1 is file pointer to open read file
fp2 is file pointer to open write file
Post file copied
Return 1 is successful or zero if error
*/
int cpyFile (FILE *fp1, FILE *fp2)
{
/* Local Definitions */
int data;
/* Statements */
fseek (fp1, 0, SEEK_END);
if (!ftell (fp1))
{
printf ("\n\acpyFile Error : file empty\n\n");
return 0;
} /* if open error */
if (fseek (fp1, 0, SEEK_SET))
return 0;
if (fseek (fp2, 0, SEEK_SET))
return 0;
while (fread (&data, sizeof (int), 1, fp1))
fwrite (&data, sizeof (int), 1, fp2);
return 1;
} /* cpyFile */
I did my best and managed to convert it, but unfortunately when I'm using it , the file that I get after the copy is empty. Below is my answer:
#include <fstream>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
if(argc!=3)
{cerr<<"invalid number of arguments. must be 3."<<endl;exit(1);}
fstream fp1(argv[1],ios::in);
if(!fp1)+{cerr<<argv[1]<<" could not be opened"<<endl;exit(1);}
fstream fp2(argv[2],ios::out);
if(!fp2)+{cerr<<"file could not be found."<<endl;exit(1);}
int data;
fp1.seekg (0,ios::end);
if (!fp1.tellg ())
{
cout<<"\n\acpyFile Error : file empty\n\n";
return 0;
} /* if open error */
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
while (fp1.read (reinterpret_cast<char*>(&data), sizeof (int)))
{
fp2.seekp(0);
fp2.write (reinterpret_cast<char*>(&data), sizeof (int));
}
return 1;
}
I did my best and everything is working fine, except that when I copy a binary file, the file that i get is empty and I have no idea why.
You need to open the file in binary mode, as others have said, by doing
fstream fp1(argv[1], ios::in | ios::binary); // combine ios::in with ios::binary
fstream fp2(argv[2], ios::out | ios::binary); // combine ios::out with ios::binary
Or you can make them ifstream (in file stream for reading only) and ofstream (out file stream, for writing only) and remove the ios::in and ios::out because ifstream implies ios::in and ofstream implies ios::out:
ifstream fp1(argv[1], ios::binary);
ofstream fp2(argv[2], ios::binary);
You need to do this because if you don't, the file will be translated when you read from or write to it for things like turning line endings from \r\n or \r to just \n, etc, which will mess up your binary data which may happen to have those bytes in them.
This:
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
Will always make your code return because seekg returns the object you call it on. It's not the equivalent of fseek in this regard because fseek returns 0 on success. So you never get to the while loop. Take those out of the if statements so that it looks like this:
fp1.seekg(0, ios::beg);
fp2.seekg(0, ios::beg);
Or if you have to have the checking, you want to do
if (!fp1.seekg (0, ios::beg)) // notice the added !
return 0;
if (!fp2.seekg (0, ios::beg)) // notice the added !
return 0;
Also, this (inside the while):
fp2.seekp(0);
Is setting the point you are going to write to to the beginning of the file. So you'll never write anything but at the beginning of the file. Just remove that line completely.
Also, you have a return inside the loop which makes it return on the first iteration. Move the return 1; outside the loop so you only return after the loop is finished. Nevermind that, misread due to the unusual brace style.
Every time you read a new data block from fp1, you rewind fp2 to the beginning of the stream, essentially discarding what you have already written to fp2. Try moving fp2.seekp(0) out of your main loop.
You have a few problems. I'd start by fixing this bit:
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
The seekg method returns a reference to the istream it's called on, so the above is equivalent to this:
fp1.seekg (0, ios::beg);
if (fp1) // i.e., if fp1 is in a valid state (as opposed to e.g. end-of-file)
return 0;
fp2.seekg (0, ios::beg);
if (fp2) // i.e., if fp2 is in a valid state (as opposed to e.g. end-of-file)
return 0;
which is obviously not what you want.
To debug your code, you can use statements like std::cout << "Got to line " << __LINE__ << std::endl; to figure out which parts of the program are actually being run. That would have found the above problem pretty quickly.
Binary files need to be opened specifically in binary mode, so where you have fstream fp1(argv[1],ios::in); you should also add an ios::binary to it like so: fstream fp1(argv[1], ios::in | ios::binary);
In the C++ code you are seeking to the beginning of the output file before writing each number, and therefore the output file will be at most 2 bytes long.

Is there a function in C++ that creates a .bin file, or is this code missing something?

I have a code that looks like this:
int main () {
fstream file;
file.open("test.bin", ios::out | ios::binary);
if(!file.is_open())
{
return -1;
}
int n = 3;
file.write(reinterpret_cast<char*>(&n), sizeof(n));
file.close();
return 0;
}
when I run it alone, it exits with -1, so obviously it failed to open "test.bin". However, if I save a blank notepad file as "test.bin", and run it, it works fine. What I am wondering is how I can get my C++ program to automatically generate an empty file "test.bin" if a file called "test.bin" does not already exist.
Your code snippet is wrong since it's trying to write to a file that you've opened for input. If you want to write to the file, simply use ios::out instead of ios::in.
If you want to open the file for reading but create it if it does not exist, you can use:
file.open("test.bin", ios::in | ios::binary);
if(!file.is_open()) {
file.open("test.bin", ios::out | ios::binary);
int n = 3;
file.write(reinterpret_cast<char*>(&n), sizeof(n));
file.close();
file.open("test.bin", ios::in | ios::binary);
if(!file.is_open()) {
return -1;
}
}
This will initialize the file with the integer 3 as the default contents, if it doesn't already exist.
If it does exist, it will leave the contents alone. In either case, you'll have the file open at the first byte.
I'd assume you could probably just do it by opening and closing a file:
if (GetFileAttributes("test.bin") == INVALID_FILE_ATTRIBUTES)
{
fstream file;
file.open("test.bin", ios::out);
file.close();
}
One option is to open for read/write and seek to the beginning of the file.
Then, you may read, write, or do whatever you wish.