I need to read file in parts ( for example by 4 bytes) and then increment numbers in files by one and then write back;
this part only fills in file by 1; How to increase this number on 1?
void Prepare()
{
//ifstream fileRead("\FILE", ios::in | ios::binary);
ofstream fileOut("\FILE.bin", ios::out | ios::binary);
int count = 10485760;
for (int i = 0; i < count-1; i++)
{
fileOut << 1;
}
fileOut.close();
}
If I understand your question, you need to read the file then write it out, changing the data. You can't really do it the way you've started.
There are two basic ways to do this. You can read the entire file into memory, then manipulate the memory, close the file, open it again for output this time (truncating it) and write it back out. This is easiest, but I don't think it's the approach you're looking for.
The other choice is to manipulate the file in place. That's trickier, but not that hard. You need to read about random access I/O (input/output). If you google for c++ random access file you'll get some good hits, but I'll show you a little bit.
// Open the file.
std::ifstream file{"file.dat"};
// Jump to a particular location in the file. Beginning is 0.
file.seekg(128);
// Read 4 bytes
char bytes[4];
file.read(bytes, 4);
// Manipulate it (more below)
int number = bytesToInt(bytes);
++number;
intToBytes(number, bytes);
// Seek again
file.seekg(128);
file.write(bytes, 4);
So the only remaining trick is that you have to convert the bytes to a number and then back into bytes. Due to endianness, it's not safe to read directly into the number. You also need to know the endianness of the data in the file. That's a separate topic you can look up if you're not already familiar with it.
(Specifically, you need to implement those two methods after verifying how the data is stored in your file.)
There may be other ways to do this, but the key to this method is the random access file.
Related
I'm writing an array af structures(factor is a structure) to a binary file like this:
factor factors[100];
ofstream fa("Desktop:\\fa.dat", ios::out | ios::binary);
fa.write(reinterpret_cast<const char*>(&factors),sizeof(factors));
fa.close();
and I run the program and save 5 records in it.in another file, I want to read the structures so I wrote this:
int i=0;
ifstream a("Desktop:\\fa.dat", ios::in | ios::binary);
factor undelivered_Factors[100];
while(a && !a.eof()){
a.read(reinterpret_cast<char*>(&undelivered_Factors),sizeof(undelivered_Factors));
cout<<undelivered_Factors[i].ID<<"\t"<<undelivered_Factors[i].total_price<<endl;
i++;
}
a.close();
but after reading and printing the saved factors it inly reads and shows the firs 2 of them in the array.why?what should i do?
Second parameter of ofstream::write and ::read is size of written memory in bytes (aka 'char' in C\C++), which is right - you're writing entire array at once. In reading procedure you had mixed up an per element and array processing. You expect to read whole array, then you print one value, then you read another 100 of records which you do not have in file, I presume. also eof() happens only when you attempt to read and it failed. If you stand on end of file,eof() isn't triggered, that's why you get two records printed.
You are doing complete read in the single call so your loop runs only one time hence it will output only first struct value. Change your while loop like this:
if(a)
{
a.read(reinterpret_cast<char*>(&undelivered_Factors),sizeof(undelivered_Factors));
}
for(int i=0; i<100; ++i)
{
cout<<undelivered_Factors[i].ID<<"\t"<<undelivered_Factors[i].total_price<<endl;
}
What I am trying to achieve is this:
Let's say I have a class Score. This class has an int variable and a char* variable.
Now when I have an object Score score, I would like to be able to save the value of those variables (I guess to a file). So now this file has an int variable and a char* variable that I can then access later to create a new Score object.
So I create Score score(10, "Bert");. I either do something like score.SaveScore(); or the score gets saved when the game is over or the program exits, it doesn't matter.
Basically I am looking for the equivalent/correct way of doing this:
score.SaveScore(FILE file)
{
file.var1 = score.score;
file.var2 = score.name;
}
I realize this is probably very stupid and not done this way whatsoever! This is just me trying to explain what I am trying to achieve in the simplest way possible.
Anyway, when I run the program again, that original Score score(10, "Bert") does not exist any more. But I would like to be able to access the saved score(from file or wherever it may be) and create another Score object.
So it may look something like:
LoadScore(FILE file)
{
Score newScore(file.var1, file.var2);
}
Again, just trying to show what I am trying to achieve.
The reason why I want to be able to access the variables again is to eventually have a Scoreboard, the Scoreboard would load a bunch of scores from the file.
Then when a new score is created, it is added to the scoreboard, compared to the other scores currently in the scoreboard and inserted in the right position (like a score of 6 would go in between 9 and 4).
I feel like this was a bit long winded but I was trying to really explain myself well! Which I hope I did!
Anyway, I am not looking for someone to tell me how to do all of that.
All I am after is how to do the initial save to a file.
Thank you for any suggestions.
I would use the <fstream> library, like this;
//example values
int x=10;
float y=10.5;
const char* chars = "some random value";
string str(chars); //make string buffer for sizing
str.resize(20); //make sure its fixed size
//open a test.txt file, in the same dir for output
std::ofstream os("test.txt", std::ios::out | std::ios::binary); //make it output binary
//(char*) cast &x, sizeof(type) for values/write to file chars for x and y
os.write((char*)&x, sizeof(int)); //only sizeof(int) starting at &x
os.write((char*)&y, sizeof(float)); //cast as a char pointer
os.write(str.data(), sizeof(char)*str.size()); //write str data
os.close();
//the file test.txt will now have binary data in it
//to read it back in, just ifstream, and put that info in new containers, like this;
int in_x = 0; //new containters set to 0 for debug
float in_y = 0;
char inchar[20]; //buffer to write 20 chars to
ifstream is("test.txt", std::ios::in | std::ios::binary); //read in binary
is.read((char*)&in_x, sizeof(int)); //write to new containers
is.read((char*)&in_y, sizeof(float));
is.read((char*)&inchar, sizeof(char)*20); //write char assuming 20 size
is.close();
//outputting will show the values are correctly read into the new containers
cout << in_x << endl;
cout << in_y << endl;
cout << inchar << endl;
I realize this is probably very stupid and not done this way whatsoever!
The entire software industry was stupid enough to have it done so many times that even a special term was invented for this operation - serialization and nearly all C++ frameworks and libraries have implemented this in a various ways.
Since question is tagged with C++ I would suggest you to look at boost serialization but there are many other implementations.
Do you need that file to be readable by a human? If yes than consider, for example, XML or JSON formats.
You don't need it be readable but want it be as compact as possible? Consider google protobuf
Just start doing it and come with a more specific question(s).
As it was mentioned before, keep strings as std:string objects rather then char*
About writing/reading to/from files in C++ read about fstream
Im currently trying to replace a text based file in my application with a binary one. Im just doing some early tests so the code isn't exactly safe but I'm having problems with the data.
When trying to read out the data it gets about half way before it starts coming back with incorrect results.
Im creating the file in c++ and my client application is c#. I think the problem is in my c++ (which I haven't used very much)
Where the problem is at the moment is I have a vector of a struct that is called DoubleVector3 which consists of 3 doubles
struct DoubleVector3 {
double x, y, z;
DoubleVector3(std::string line);
};
Im currently writing the variables individually to the file
void ObjElement::WriteToFile(std::string file) {
std::ofstream fileStream;
fileStream.open(file); //, ios::out | ios::binary);
// ^^problem was this line. it should be
// fileStream.open(file, std::ios_base::out | std::ios_base::binary);
fileStream << this->name << '\0';
fileStream << this->materialName << '\0';
int size = this->vertices.size();
fileStream.write((char*)&size,sizeof(size));
//i have another int written here
for (int i=0; i<this->vertices.size(); i++) {
fileStream.write((char*)&this->vertices[i].x, 8);
fileStream.write((char*)&this->vertices[i].y, 8);
fileStream.write((char*)&this->vertices[i].z, 8);
}
fileStream.close();
}
When I read the file in c# the first 6 sets of 3 doubles are all correct but then I start getting 0s and minus infinities
Am I doing anything obviously wrong in my WriteToFile code?
I have the file uploaded on mega if anyone needs to look at it
https://mega.co.nz/#!XEpHTSYR!87ihtCfnGXJJNn13iE6GIpeRhlhbabQHFfN88kr_BAk
(im writing the name and material in first then the number of vertices before the actual list of vertices)
Small side question - Should I delimit these doubles or just add them in one after the other?
To store binary data in a stream, you must add std::ios_base::binary to the stream's flags when opening it. Without this, the stream is opened in text mode and line-ending conversions can happen.
On Windows, line-ending conversions mean inserting a byte 0x0D (ASCII for carriage-return) before each 0x0A byte (ASCII for line-feed). Needless to say, this corrupts binary data.
Good day,
I'm working on a program, which reads in a binary file (functions for read in are given and work) and then write the modified information back in another binary file. (I'm changing between two formats.) If I use std::cout to give out the numbers to the console right before (or after) I use ofstream to write them in a file. I get out the numbers I anticipate, but if I know input them into ofstream via << or write and then look at the contents of the file. (The conversion from this format to the original one exists and I can use it.) Then I get carbage.
struct Record {
unsigned latch;
float e, x, y, u, v, wt;}
I read in the given file and modify the numbers I read in. (The following is part of the main-function). Header h is defined and there exists a default constructor. phsp.read and copy are given and work. Reclen corresponds to the Record length and ensures, that the header is written right, because it can be different for different inputs.
std::ofstream outs;
outs.open(outfile, std::ios::out | std::ios::trunc);
Header h;
outs.write((char*) &h, reclen - 5);
for (int i=0; i<nMax; ++i){
phsp.read(mp);
copy(mp, ep);
Record rec;
Modify numbers and putting them into rec, which is a struct and given above. Rec should be written into the file
outs<<rec.latch<<rec.e<<rec.x<<rec.y<<rec.u<<rec.v<<rec.wt;
outs.write((char*) &rec.latch, 4);outs.write((char*) &rec.e, 4);
outs.write((char*) &rec.x, 4); outs.write((char*) &rec.y, 4);
outs.write((char*) &rec.u, 4);outs.write((char*) &rec.v, 4);
outs.write((char*) &rec.wt, 4);
outs.write((char*) &rec, reclen);
}
Not one of this writes, what I want into the file, but if I give out the numbers through std::cout and the console. I get the expected numbers.
std::cout<<rec.latch<<' '<<rec.e<<' '<<rec.x<<' '<<rec.y<<' '<<rec.u<<' '<<rec.v<<
' '<<rec.wt<<'\n';
I also checked the outs stream with good() and I also checked that the file is open. I can also write into the file. Also the write and the << output don't give the same output (could be expected). I checked the size of the rec.i and it also corresponds to the size of the structs.
At the end I change the header again, because I have now new information.
outs.seekp(5);
outs.write((char*) &h, reclen - 5);
outs.close();
There I also have the same problem, with false numbers. I noticed that a number of 0 corresponds to 0, but the number 1 is converted to 16777216 for a unsigned int number.
I hope you can help me, I have no idea what is wrong.
You need to decide whether your new file format is supposed to use binary or text representation for data.
Typically when you use ofstream::write() method you're saving your data in binary format, which means it will be represented as an array of bytes with the length equal to the data structure you're writing. Therefore what you will find in the file will not be the number but its binary representation which generally looks like rubbish if seen as text.
You may see the number by using a hex editor, or you can read it back and then interpret it as a type of your choice. For example:
float number;
ifs.read(&number, sizeof(float); // read in the 4 bytes from the file into a float
This is an equivalent of doing:
char* buffer = new char[sizeof(float)];
ifs.read(buffer, sizeof(float)];
float f = *(reinterpret_cast<float*>(buffer));
If you printed out the contents of the buffer before casting it, you'd see the same rubbish you see in your file. Note that reading and writing binary data requires ios::binary flag set.
operator<< is typically used for writing data as text. It is less efficient in terms of space and speed, but has an advantage of being human readable. Writing data as text is as simple as printing it to the screen, e.g.
std::ofstream ofs;
ofs.open("file.txt");
float f = 1.337f;
ofs << "My float: " << f;
std::cout << "My float: " << f;
If you use above code in the same scope, there is no way for the contents in your file to be different from what's shown on your screen.
Finally make sure that your variables are initialized before using them, as in the code you've posted you're not doing it. E.g.
Header h; // <-- this probably contains rubbish until initialized with some values
outs.write((char*) &h, reclen - 5); // <-- writes rubbish
Edit: I'm trying to convert a text file into bytes. I'm not sure if the code is turning it into bytes or not. Here is the link to the header so you can see the as_bytes function.
link
#include "std_lib_facilities.h"
int main()
{
cout << "Enter input file name.\n";
string file;
cin >> file;
ifstream in(file.c_str(), ios::binary);
int i;
vector<int> bin;
while(in.read(as_bytes(i), sizeof(int)))
bin.push_back(i);
ofstream out(file.c_str(), ios::out);
for(int i = 0; i < bin.size(); ++i)
out << bin[i];
keep_window_open();
}
Note that now the out stream just outputs the contents of the vector. It doesn't use the write function or the binary mode. This converts the file to a large line of numbers - is this what I'm looking for?
Here is an example of the second code's file conversion:
that guy likes to eat lots of pie (not sure if this was exact text)
turns to
543518319544825700191924850016351970295432362115448292821701667182186922608417526375411952522351186935715718643976841768956006
The reason your first method didn't change the file is because all files are stored in the same way. The only "difference" between text files and binary files is that text files contain only bytes that can be shown as ASCII characters, while binary files* have a much more random variety and order of bytes. So you are reading bytes in as bytes and then outputting them as bytes again!
*I'm including Unicode text files as binary, since they can have multiple bytes to denote one character point, depending on the character point and the encoding used.
The second method is also fairly simple. You are reading in the bytes, as before, and storing them in integers (which are probably 4 bytes long). Then you are just printing out the integers as if they are integers, so you are seeing a string of numbers.
As for why your first method cut off some of the bytes, you're right in that it's probably some bug in your code. I thought it was more important to explain what the ideas are in this case, rather than debug some test code.