Why am i Getting garbage value when reading a binary file? - c++

For the sake of simplicity I wrote a simple code to reproduce my problem. As you can see on the code i created a struct with two members then I created and array of the struct type then initialized it student newStudent[3] ={{"joseph",20}, {"yonas",30},{"miryam",40}};. I stored all the info from the struct to a binary file newFile.write(reinterpret_cast<char*>(newStudent), 3 * sizeof(student));(everything is fine until here) then i created another array student loadedStudent[3]; to load into, all the data from the binary file and output the loaded data using a for loop cout<<"Name: "<<loadedStudent[i].name<<"Age: "<<loadedStudent[i].age<<endl;. The problem is that the data i stored is joseph",20, "yonas",30,"miryam",40 but the program is outputting garbage values Name: 8H???Age: 1 Name: J???Age: 1 Name: ?I???Age: 32766.
Why is that?
#include <iostream>
#include <fstream>
using namespace std;
struct student{
char name[10];
int age;
};
int main()
{
student newStudent[3] ={{"joseph",20}, {"yonas",30},{"miryam",40}};
fstream newFile;
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
//for(int i = 0; i<3; i++){
//cout<<"Name: "<<newStudent[i].name<<" Age: "<<newStudent[i].age<<endl;
//}
if(newFile.is_open()){
newFile.write(reinterpret_cast<char*>(newStudent), 3 * sizeof(student));
}else cout<<"faild to open file";
student loadedStudent[3];
newFile.seekg(0, ios::beg);
if(newFile.is_open()){
newFile.read(reinterpret_cast<char*>(loadedStudent), 3 * sizeof(student));
newFile.close();
}else cout<<"faild to open file";
for(int i = 0; i<3; i++){
cout<<"Name: "<<loadedStudent[i].name<<"Age: "<<loadedStudent[i].age<<endl;
}

When you opened the file you only opened it as output ios::out you shoul've also included ios::in so you can access the file. Now you're printing the indeterminate values of an uninitialized array.
change this
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
into
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::in | ios::binary);

newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
This is opening the file for output only. You need ios::in | ios::out to be able to both read and write.

Related

c++ fstream not writing to object properly

I have the following code:
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include "Person.h"
using namespace std;
int main()
{
// ========================================================================================
// part a - initialiaze 100 records, lastName = "unassigned", firstName = "", age = 0
ofstream outPerson_0("nameage.dat", ios::out | ios::binary);
// exit program if ofstream could not open file
if (!outPerson_0)
{
cerr << "File could not be opened." << endl;
exit(EXIT_FAILURE);
} // end if
Person blankPerson("unassigned", "", 0); // constructor zeros out each data member
// output 100 blank records to file
for (int i = 0; i < 100; ++i)
outPerson_0.write(reinterpret_cast< const char * >(&blankPerson), sizeof(Person));
// ========================================================================================
// part b - input 10 first names and ages and write them to file
string firstName;
string lastName;
int age;
fstream outPerson_1("nameage.dat", ios::in | ios::out | ios::binary);
// exit program if fstream cannot open file
if (!outPerson_1)
{
cerr << "File could not be opened." << endl;
exit(EXIT_FAILURE);
} // end if
// iterate 10 times to get first names and ages
for (int i = 0; i < 10; ++i)
{
// get user input
cout << "Enter last name, first name and age (space separated): ";
// set dummy values in object
std::string s = std::to_string(i);
blankPerson.setLastName(s);
blankPerson.setFirstName(s);
blankPerson.setAge(i);
// seek position in file of user-specified record, using i
auto pos = (i) * sizeof(Person);
outPerson_1.seekp(pos);
// write user-specified information in file
outPerson_1.write(reinterpret_cast<const char *>(&blankPerson), sizeof(Person));
}
// ========================================================================================
// part c - update record with no info
}
Part a populated 100 objects with dummy values, and writes to file. Part b updates the first 10 objects with dummy values generated by iterator i. For some strange reason, part b does not work properly. Could someone tell me why? The result is exactly the same as when I run part a alone.
Normally object is not suggested to write to file directly, but just by case, your code has other problem:
the ofstream and fstream instances have its own internal buffer, the data will be written into internal buffer before flushing/syncing to underlying file.
Before quitting the program,
fstream outPerson_1 will destroyed
its internal buffer will be flushed to file "nameage.dat"
ofstream outPerson_0 is destroyed
its internal buffer will be flushed to file "nameage.dat" again
(as for why, it is another topic, don't talk here)
Since the data in outPerson_0 is more than the data in outPerson_1, so the outPerson_1 data is overwritten, and then you can't see it, if you write more data into outPerson_1, you will observe it.
There may be 2 options for your code:
Option#1:
flush the data after writing the first 100 person data
// output 100 blank records to file
for (int i = 0; i < 100; ++i)
outPerson_0.write(reinterpret_cast< const char * >(&blankPerson), sizeof(Person));
outPerson_0.flush();
Option#2:
Add ios::app flag to let ofstream/fstream to append the data to the file
ofstream outPerson_0("nameage.dat", ios::out | ios::binary | ios::app);
fstream outPerson_1("nameage.dat", ios::in | ios::out | ios::binary | ios::app);

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?

Create file using fstream if it doesn't exist that utilizes seekp/seekg?

fstream file(file_1.c_str(), ios::out | ios::in | ios::ate); //convert string to const char*
Error if File does not exist. if ( ! file ) = true
fstream file(file_1.c_str(), ios::out | ios::in | ios::app); //convert string to const char*
using ios::app seekg & seekp functions not working. file.seekg(4, ios_base::beg);
I would like to have:
USER input file name
create file if NON existing
use seekg & seekp;
Not remove the file if you run the program again.
If I understand you correctly, you need something like this:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
string name;
std::cin>>name;
std::ofstream file (name.c_str());
outfile << "Text in file." << std::endl;
file.close();
return 0;
}

writing data to afile in fixed amount causing it to repaet the data in file c++

I have this program and i want to read the data in small parts like 2 kb each and then write it to a file but when i try to do it its reading and writing my file four times. here is my code:
#include<fstream>
#include<iostream>
using namespace std;
ifstream::pos_type size; // use if file is larger than 2 gb
int main()
{
char *memblock=0;
ifstream in("file.txt", ios::in | ios::binary | ios::ate);
ofstream in1("file1.txt", ios::out | ios::binary | ios::ate);
size = in.tellg();
cout << "Size of file "<< size << endl;
float sz= size/2048.0;
int sizechck = ceil(sz);
cout<< "size is "<<sizechck;
if(in.is_open())
{
memblock = new char [2048];
for (j=0;j<=sizechck;j++)
{
in.seekg (j*2048,ios::beg);
in.read (memblock, 2048);
in1.write(memblock,2048);
}
}
system("pause");
return 0;
}
You're reading and writing 4096 bytes, but you're seeking 2048. (you're writing to unallocated memory btw).
You don't need to seek at all. Read and write are moving the file pointer accordingly.

Write to the middle of an existing binary file 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;
}`