How to write a hexadecimal literally to file? - c++

I have a little problem, I want to write something like that 0xff to a file, and I have done it:
ofstream file;
file.open(this->dbFile, ios::app | ios::binary);
const char prefix = 0xff;
file.write(&prefix, sizeof(char));
The previous example works well, but this is not my issue.
I want to write the previous example with writing the hexadecimal literally like the following:
ofstream file;
file.open(this->dbFile, ios::app | ios::binary);
file.write((const char*)0xff, sizeof(char));
But unfortunately, there is a runtime error occurs with the second example.
I know there's something wrong with the data conversion, but what is it?

first char is often used as a synonym for the non existing type byte, however you could easily make your own using statement like
#include <cstdint>
using byte_t = int8_t;
Consider this line file.write((const char*)0xff, sizeof(char)); as ostream::Write(const byte_t* pointerToArrayOfData, std::streamsize sizeOfData). 0xFF is the data you want to write but not an address of an array holding your data. sizeof(char)=sizeof(byte_t)=1 can be neglected, the method is designed to write single bytes. However you can use this to serialize custom types like
struct Point { int8_t x, y; };
array<Point, 4> myRectangle {/* */};
file.write(&myRectangle, sizeof(Point) * array.size());
file.write(&myRectangle, sizeof(array<Point, 4>));
Note this is platform dependent and you should always consider the generated file can only be read on the same system you created it. If you want to transfer binary data please consider some abstractions like protobuf.
TLDR;
using byte_t = char;
void write_binary_data(std::ostream& ostream, byte_t* data, size_t count)
{
ostream.write(data, count);
}
using binary_data_t = std::vector<byte_t>;
void write_binary_data(std::ostream& ostream, const binary_data_t data)
{
write_binary_data(ostream, data.data(), data.size());
}
ofstream file;
file.open(this->dbFile, ios::app | ios::binary);
write_binary_data(file, { 0xFF, 0x00, 0xFF });

Related

Weird behavior writing/reading simple binary file

I'm writing and reading on a binary file. I'm getting small errors when outputting the reads.
The strings are there but with little snippets like: (I"�U) (�U) appended to the end of ~30% of them
I'm using g++ compiler on Ubuntu
Simplified code:
struct Db_connection
{
public:
string name;
}
int Db_connection::write_config()
{
ofstream config_f("config.dat", std::ios_base::binary | std::ios_base::out); //open file
string str = name;
int size = str.length();
config_f.write(reinterpret_cast<char *>(&size), sizeof(int)); // write size of string in int size chunk
config_f.write(str.c_str(), size); //write string
config_f.close();
return 0;
}
Db_connection read_config()
{
ifstream config_f("config.dat", std::ios_base::binary | std::ios_base::in);
Db_connection return_obj;
int size;
string data;
config_f.read(reinterpret_cast<char *>(&size), sizeof(int)); // read string size
char buffer[size];
config_f.read(buffer, size); // read string
data.assign(buffer);
return_obj.name = data;
return return_obj;
}
Is there anything obvious I am messing up? Does this have to do with Endian? I tried to minimize the code to it's absolute essentials
The actual code is more complex. I have a class holding vectors of 2 structs. 1 struct has four string members and the other has a string and bool. These fuctions are actually a member of and return (respectively) that class. The fuctions loop through the vectors writing struct members sequentially.
Two oddities:
To debug, I added outputs of the size and data variables on each iteration in both the read and write functions. size comes out accurate and consistent on both sides. data is accurate on the write side but with the weird special characters on the read side. I'm looking at outputs like:
Read Size: 12
Data: random addy2�U //the 12 human readable chars are there but with 2 extra symbols
The final chunk of data (a bool) comes out fine every time, so I don't think there is a file pointer issue. If its relevant: every bool and int is fine. Its just a portion of the strings.
Hopefully i'm making a bonehead mistake and this minimized code can be critiqued. The actual example would be too long.
Big thanks to WhozCraig,
The following edit did, indeed, work:
Db_connection read_config()
{
ifstream config_f("config.dat", std::ios_base::binary | std::ios_base::in);
Db_connection return_obj;
int size;
string data;
config_f.read(reinterpret_cast<char *>(&size), sizeof(int)); // read string size
vector<char> buff(size);
config_f.read(buff.data(), size);
data = string(buff.begin(), buff.end());
return_obj.name = data;
return return_obj;
}
As paddy pointed out directly and WhozCraig alluded to, this code still needs to implement a standardized, portable data type for recording the integer properly into binary and the write function needs to be rethought as well.
Thank you very much to the both of you. I read like 5-8 top search results for "cpp binary i/o" before writing my code and still ended up with that mess. You guys saved me hours/days of my life.

write user-defined structure to file, in binary mode

In a c++ textbook I learn that I should be able to do this (write/read a user-defined type to a file, in binary mode):
struct mystruct
{
int a;
double b;
};
void main()
{
struct mystruct s = {1,2.0};
std::ofstream out("binary.dat", std::ios::out | std::ios::binary);
out.write(reinterpret_cast< const char* > (&s), sizeof(struct mystruct));
}
The code compiles and runs but the resultant file is cannot be read by text-editors. then I use binary mode to read the file:
std::ifstream in("binary.dat", std::ios::in | std::ios::binary);
struct mystruct t;
in.read( reinterpret_cast<char*> (&t), sizeof(struct mystruct));
However it turns out it's unsuccessful (it doesn't get the numbers 1 and 2.0). Maybe I interpret the textbook wrongly..., or maybe something wrong with the code?
but the resultant file is cannot be read by text-editors
That's because you didn't write text to the file. The data cannot be interpreted meaningfully in any character encoding. You can use hexdump or similar tool for a meaningful representation.
Maybe I interpret the textbook wrongly..., or maybe something wrong with the code?
I don't think so. There's nothing wrong with the pieces of code individually except weird formatting and redundant keywords. Besides non-portability of the file of course. And the invalid return type of main.
However, perhaps what you did was a single program like this:
// ...
std::ofstream out("binary.dat", std::ios::binary);
out.write(reinterpret_cast<const char*>(&s), sizeof(s));
std::ifstream in("binary.dat", std::ios::binary);
in.read(reinterpret_cast<char*>(&t), sizeof(t));
// ...
There's a bug here. As you can see from the documentation, ostream::write writes to it's associated stream buffer. It's not until ostream::flush is called that the buffer is written to output. So, in the above code, the file is empty at the time it is read. This can obviously be fixed by calling out.flush() before reading the file.
As mentioned in comments, this is not at all portable. What that means is that a file written by your program on one computer may not be readable by your program on another computer. Even on the same computer, two programs compiled with different compiler options may not have the same memory layout for the class.
Why not do the standard way. It's simple and easy to understand
struct mystruct {
int a;
double b;
friend std::ostream & operator <<(std::ostream & out, mystruct & mys) {
out << mys.a << " " << mys.b << std::endl;
return out;
}
friend std::istream & operator >>(std::istream & in, mystruct & mys) {
in >> mys.a >> mys.b;
return in;
}
};
The usage will be simple now. For example
mystruct s;
To read
std::ifstream in("binary.dat");
in >> s;
To write
std::ofstream out("binary.dat");
out << s;
You can also overload std::string operator inside the struct if you want to serialize
operator std::string() const {
std::stringstream ss;
ss << a << " " << b;
return ss.str();
}

Binary writing of INT16 on c++

I have found out this way:
ofstream out("test", ios::out | ios::binary);
UINT16 myint16=16;
out.write((char*)&myint16, sizeof(myint16));
But are there ways to write INT16 binary without declaring a variable?
You can write your own operator<< like that:
std::ofstream& operator<<(std::ofstream& ofs, UINT16 d) {
ofs.write((char*)&d, sizeof(UINT16));
return ofs;
}
int main(int, char*[])
{
ofstream out("test", ios::out | ios::binary);
out << static_cast<UINT16>(16); // no variable declared
}
also with C++11 you could use user defined literals to make it even shorter:
inline UINT16 operator "" _u(unsigned long long value)
{
return static_cast<UINT16>(value);
}
and then:
out << 16_u;
But are there ways to write INT16 binary without declaring a variable?
Yes, you can use a c-string literal:
out.write("\0\0", 2);
To output correct INT16 values this way, you'll need to know the endianess of the machine where you're compiling and running your program. E.g. to output decimal 16
out.write("\x01\x00", 2); // 16 in big endian format
out.write("\x00\x01", 2); // 16 in little endian format

Writing struct of vector to a binary file in c++

I have a struct and I would like to write it to a binary file (c++ / visual studio 2008).
The struct is:
struct DataItem
{
std::string tag;
std::vector<int> data_block;
DataItem(): data_block(1024 * 1024){}
};
I am filling tha data_block vector with random values:
DataItem createSampleData ()
{
DataItem data;
std::srand(std::time(NULL));
std::generate(data.data_block.begin(), data.data_block.end(), std::rand);
data.tag = "test";
return data;
}
And trying to write the struct to file:
void writeData (DataItem data, long fileName)
{
ostringstream ss;
ss << fileName;
string s(ss.str());
s += ".bin";
char szPathedFileName[MAX_PATH] = {0};
strcat(szPathedFileName,ROOT_DIR);
strcat(szPathedFileName,s.c_str());
ofstream f(szPathedFileName, ios::out | ios::binary | ios::app);
// ******* first I tried to write this way then one by one
//f.write(reinterpret_cast<char *>(&data), sizeof(data));
// *******************************************************
f.write(reinterpret_cast<const char *>(&data.tag), sizeof(data.tag));
f.write(reinterpret_cast<const char *>(&data.data_block), sizeof(data.data_block));
f.close();
}
And the main is:
int main()
{
DataItem data = createSampleData();
for (int i=0; i<5; i++) {
writeData(data,i);
}
}
So I expect a file size at least (1024 * 1024) * 4 (for vector)+ 48 (for tag) but it just writes the tag to the file and creates 1KB file to hard drive.
I can see the contents in while I'm debugging but it doesn't write it to file...
What's wrong with this code, why can't I write the strcut to vector to file? Is there a better/faster or probably efficient way to write it?
Do I have to serialize the data?
Thanks...
Casting a std::string to char * will not produce the result you expect. Neither will using sizeof on it. The same for a std::vector.
For the vector you need to use either the std::vector::data method, or using e.g. &data.data_block[0]. As for the size, use data.data_block.size() * sizeof(int).
Writing the string is another matter though, especially if it can be of variable length. You either have to write it as a fixed-length string, or write the length (in a fixed-size format) followed by the actual string, or write a terminator at the end of the string. To get a C-style pointer to the string use std::string::c_str.
Welcome to the merry world of C++ std::
Basically, vectors are meant to be used as opaque containers.
You can forget about reinterpret_cast right away.
Trying to shut the compiler up will allow you to create an executable, but it will produce silly results.
Basically, you can forget about most of the std::vector syntactic sugar that has to do with iterators, since your fstream will not access binary data through them (it would output a textual representation of your data).
But all is not lost.
You can access the vector underlying array using the newly (C++11) introduced .data() method, though that defeats the point of using an opaque type.
const int * raw_ptr = data.data_block.data();
that will gain you 100 points of cool factor instead of using the puny
const int * raw_ptr = &data.data_block.data[0];
You could also use the even more cryptic &data.data_block.front() for a cool factor bonus of 50 points.
You can then write your glob of ints in one go:
f.write (raw_ptr, sizeof (raw_ptr[0])*data.data_block.size());
Now if you want to do something really too simple, try this:
for (int i = 0 ; i != data.data_block.size() ; i++)
f.write (&data.data_block[i], sizeof (data.data_block[i]));
This will consume a few more microseconds, which will be lost in background noise since the disk I/O will take much more time to complete the write.
Totally not cool, though.

How to write a file byte by byte using c++

How to write a file byte by byte using c++?
unsigned short array[2]={ox20ac,0x20bc};
if i have a hexadecimal value 0x20ac how can i write it byte by byte in a file using c++
You can try something like this:
#include <fstream>
...
ofstream fout;
fout.open("file.bin", ios::binary | ios::out);
int a[4] = {100023, 23, 42, 13};
fout.write((char*) &a, sizeof(a));
fout.close();
One option, using standard C++ library:
#include <fstream>
#include <assert.h>
void main()
{
unsigned short array[2]={ox20ac,0x20bc};
std::ofstream file;
file.open("C:/1.dat", std::ios_base::binary);
assert(file.is_open());
for(int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
file.write((char*)(array + i * sizeof(array[0])), sizeof(array[0]));
file.close();
}
Alternatively, you can easily write your whole data in one go (without a loop):
file.write((const char*)array, sizeof(array));
To open an output file, use ofstream (output file stream, a subclass of ostream). Use the ios_base::binary mode (as second argument in the constructor or the open() member function) if you're not sure whether your output is human-readable text (ASCII).
To write a single byte, use the ostream member function "put". To write more than one byte at a time, use the ostream member function "write".
There are ways of taking data types (int, for example) longer than one byte and using them as arrays of bytes. This is sometimes called type-punning and is described in other answers, but beware of endianness and different sizes of data types (int can be 2-8 bytes), which can be different on different machines and compilers.
To test your output, reopen it as an input file and print the bytes.
ifstream in("myfile.txt", ios_base::binary);
while(!in.eof()) printf("%02X ", in.get()); //print next byte as a zero-padded width-2 capitalized hexadecimal).
in.close();
Or just use a hex editor like normal people.
you can use write function or ostream .
Use c++ function is ostream.