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
Related
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 });
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();
}
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.
I have my struct:
struct a
{
int x;
float f;
double d;
char c;
char s[50];
};
and I wish append each time into my timer schedule into a binary file.
// declaration
std::ofstream outFile;
// constructor:
outFile.open( "save.dat", ios::app );
// tick:
outFile << a << endl;
but inside the save.dat appears only this:
0C3A0000..0C3A0000..0C3A0000..0C3A0000..0C3A0000..0C3A0000..0C3A0000..0C3A0000..0C3A0000..
thanks in advance
What you're currently doing is writing the address of the struct definition.
What you want to do is use ostream::write
outfile.write(reinterpret_cast<char*>(&myStruct), sizeof(a));
This will work as long as your struct is a POD (Plain Old Data) type (which your example is). POD type means that all members are of fixed size.
If you on the other hand have variable sized members then you would need to write out each member one by one.
A sensible way to serialize custom objects is to overload your own output stream operator:
std::ostream & operator<<(std::ostream & o, const a & x)
{
o.write(reinterpret_cast<char*>(&x.x), sizeof(int));
o.write(reinterpret_cast<char*>(&x.f), sizeof(float));
/* ... */
return o;
}
a x;
std::ofstream ofile("myfile.bin", std::ios::binary | std::ios::app);
ofile << a;
This is still platform-dependent, so to be a bit safer, you should probably use fixed-width data types like int32_t etc.
It might also not be the best idea semantically to use << for binary output, since it's often used for formatted output. Perhaps a slightly safer method would be to write a function void serialize(const a &, std::ostream &);
std::bitset has a to_string() method for serializing as a char-based string of 1s and 0s. Obviously, this uses a single 8 bit char for each bit in the bitset, making the serialized representation 8 times longer than necessary.
I want to store the bitset in a binary representation to save space. The to_ulong() method is relevant only when there are less than 32 bits in my bitset. I have hundreds.
I'm not sure I want to use memcpy()/std::copy() on the object (address) itself, as that assumes the object is a POD.
The API does not seem to provide a handle to the internal array representation from which I could have taken the address.
I would also like the option to deserialize the bitset from the binary representation.
How can I do this?
This is a possible approach based on explicit creation of an std::vector<unsigned char> by reading/writing one bit at a time...
template<size_t N>
std::vector<unsigned char> bitset_to_bytes(const std::bitset<N>& bs)
{
std::vector<unsigned char> result((N + 7) >> 3);
for (int j=0; j<int(N); j++)
result[j>>3] |= (bs[j] << (j & 7));
return result;
}
template<size_t N>
std::bitset<N> bitset_from_bytes(const std::vector<unsigned char>& buf)
{
assert(buf.size() == ((N + 7) >> 3));
std::bitset<N> result;
for (int j=0; j<int(N); j++)
result[j] = ((buf[j>>3] >> (j & 7)) & 1);
return result;
}
Note that to call the de-serialization template function bitset_from_bytes the bitset size N must be specified in the function call, for example
std::bitset<N> bs1;
...
std::vector<unsigned char> buffer = bitset_to_bytes(bs1);
...
std::bitset<N> bs2 = bitset_from_bytes<N>(buffer);
If you really care about speed one solution that would gain something would be doing a loop unrolling so that the packing is done for example one byte at a time, but even better is just to write your own bitset implementation that doesn't hide the internal binary representation instead of using std::bitset.
Answering my own question for completeness.
Apparently, there is no simple and portable way of doing this.
For simplicity (though not efficiency), I ended up using to_string, and then creating consecutive 32-bit bitsets from all 32-bit chunks of the string (and the remainder*), and using to_ulong on each of these to collect the bits into a binary buffer.
This approach leaves the bit-twiddling to the STL itself, though it is probably not the most efficient way to do this.
* Note that since std::bitset is templated on the total bit-count, the remainder bitset needs to use some simple template meta-programming arithmetic.
edit: The following does not work as intended. Appearently, "binary format" actually means "ASCII representation of binary".
You should be able to write them to a std::ostream using operator<<. It says here:
[Bitsets] can also be directly inserted and extracted from streams in binary format.
As suggested by guys at gamedev.net, one can try using boost::dynamic_bitset since it allows access to internal representation of bitpacked data.
I can't see an obvious way other than converting to a string and doing your own serialization of the string that groups chunks of 8 characters into a single serialized byte.
EDIT: Better is to just iterate over all the bits with operator[] and manually serialize it.
this might help you, it's a little example of various serialization types.
I added bitset and raw bit values, that can be used like the below.
(all examples at https://github.com/goblinhack/simple-c-plus-plus-serializer)
class BitsetClass {
public:
std::bitset<1> a;
std::bitset<2> b;
std::bitset<3> c;
unsigned int d:1; // need c++20 for default initializers for bitfields
unsigned int e:2;
unsigned int f:3;
BitsetClass(void) { d = 0; e = 0; f = 0; }
friend std::ostream& operator<<(std::ostream &out,
Bits<const class BitsetClass & > const m
{
out << bits(my.t.a);
out << bits(my.t.b);
out << bits(my.t.c);
std::bitset<6> s(my.t.d | my.t.e << 1 | my.t.f << 3);
out << bits(s);
return (out);
}
friend std::istream& operator>>(std::istream &in,
Bits<class BitsetClass &> my)
{
std::bitset<1> a;
in >> bits(a);
my.t.a = a;
in >> bits(my.t.b);
in >> bits(my.t.c);
std::bitset<6> s;
in >> bits(s);
unsigned long raw_bits = static_cast<unsigned long>(s.to_ulong());
my.t.d = raw_bits & 0b000001;
my.t.e = (raw_bits & 0b000110) >> 1;
my.t.f = (raw_bits & 0b111000) >> 3;
return (in);
}
};