HI im trying to write to a txt file in binary.
now i wrote this code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char* f = "abc";
ofstream ofile("D:\\foobar.txt", ios_base::out | ios_base::binary);
ofile.write(f, sizeof(char*));
return 0;
}
now it writes "abc" but not in binary.
can someone please tell me how to write it in binary.
First of all, you write the wrong size and might go out of bounds. Use strlen instead to get the length of the string.
Secondly, think about how a letter like 'a' is stored in memory in the computer. It's is stored in whatever encoding the compiler and operating system uses, which is most likely ASCII. When you write that letter to a file it will write the value stored in memory to the file, and if you read the file using a program which is able to decipher the encoding it will show you the letter.
I'm just guessing here, but I think you expected binary format to write actual ones and zeroes as text. Well you do write ones and zeroes, not as text but as individual bits. And when all those bits are put together into bytes you get the bytes as they are stored in memory. If you look at the file in a hex-editor you will the the actual values, and you might even be able to find a program that shows you the actual binary values as ones and zeros.
Related
I have some bits stored in a C++ std::string, e.g. 0001010100011 and I need to dump these into a binary file without wasting space.
I would group every 8 bits together and output a character for each group, for example 000101010 and 00011.
Is there any better way to do this?
Supply each 8-bit chunk string bitchunk to unsigned char c = std::stoi(bitchunk, nullptr, 2); and you'll get a char representation of it in c ready to be stored or manipulated further.
Don't forget to #include <string>
I was given a file with data stored in a custom format, for example, "data.asd", and tasked with extracting the information out of it. I was given a file specification of the ".asd" format.
All asd files begin at 0x0 which starts with the 5 bytes "Hello" and a 6th one for the \0 termination. Next 32 bits is a pointer to an entry list, which is an array of 127 entries. Each entry contains a 16 char null terminated string, a pointer to some data, and a size variable that tells the size of the data. The value 0xFFFFFFFF signifies the end of the list.
I've look into using the C++ boost serializing library, but get errors when I tried to open the file. I'm assuming boost can only read files it has wrote.
std::ifstream ifs("data.asd");
boost::archive::binary_iarchive in_arch(ifs);
I've since checked out serializing "manually" by opening in ifstream, copying the binary file into a vector, and then using memmove.
ifs.open(fileName, ios::in | ios::binary);
//copy all contents in binary into buffer
vector<char> buffer((
istreambuf_iterator<char>(ifs)),
(istreambuf_iterator<char>()));
memmove(s, &buffer.at(0), 6); // move char array 'hello' into string s
I should be able to figure out where the data, entry list, and strings end by checking for termination bits. That way I can get by using memmove and serialize the file by checking bits.
For my case, is there any better option? If i am stuck using memmove, how do I figure out what the pointers point to? Using memmove I was able to move the six bits into a string 's' and rebuild the variable, but I'm unsure how to handle the pointers.
You could memory map things and use Boost Endian.
Alternatively you could use Boost Spirit's Binary parsers: https://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/qi/reference/binary.html
There's an example:
std::uint32_t length;
bool valid = qi::parse(first, last,
"Hello" >> qi::little_word >> char_('\0'), length);
My problem is that I have a string in hex representation say:
036e. I want to write it to a binary file in the same hex representation. I first converted the string to an integer using sstrtoul() function. Then
I use fwrite() function to write that to a file. Here is the code that I wrote. I get the following output in my file after running this:
6e03 0000
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ofstream fileofs("binary.bin", ios::binary | ios::out);
string s = "036e";
int x = strtoul(s.c_str(), NULL, 16);
fileofs.write((char*)&x, sizeof(int));
fileofs.close();
}
While the result that I expect is something like this:
036e
Can anybody explain exactly what I'm doing wrong over here?
Your problem has to do with endianees and also with the size of an integer.
For the inverting bytes the explanation is that you are running in a little-endian system.
For the extra 2 zeros the explanation is that you are using a 32 bit compiler where ints have 4 bytes.
There is nothing wrong with your code as long as you are going to use it always in 32 bit, little-endian systems.
Provided that you keep the system, if you read your integers from the file using similar code you'll get the right values (your first read integer will be 0x36E).
To write the data as you wish you could use exactly the same code with minor changes as noted bellow:
unsigned short x = htons(strtoul(s.c_str(), NULL, 16));
fileofs.write((char*)&x, sizeof(x));
But you must be aware that when you read back the data you must convert it to the right format using ntohs(). If you write your code this way it will work in any compiler and system as the network order is allways the same and the converting functions will only perform data changes if necessary.
You can find more information on another thread here and in the linux.com man page for those functions.
If you want 16 bits, use a data type that is guaranteed to be 16 bits. uint16_t from cstdint should do the trick.
Next Endian.
This is described in detail many places. The TL;DR version is some systems, and virtually every desktop PC you are likely to write code for, store their integers with the bytes BACKWARD. Way out of scope to explain why, but when you get down into the common usage patterns it does make sense.
So What you see as 036e is two bytes, 03 and 6e, and stored with the lowest significance byte, 6e, first. So that the computer sees is a two byte value containing 6e03. This is what is written to the output file unless you take steps to force an ordering on the output.
There are tonnes of different ways to force an ordering, but lets focus on the one that both always works(even when porting to a system that is already big endian) and is easy to read.
uint16_t in;
uint8_t out[2];
out[0] = (in >> 8) & 0xFF; // put highest in byte in first out byte
out[1] = in & 0xFF; // put lowest in byte in second out byte
out is then written to the file.
Recommended supplementary reading: Serialization This will help explain the common next problem: "Why my strings crash my program after I read them back in?"
I have a question about put or other derivatives of in fstream.h. Can I make sure about portability of the code when I want to simply write something like so:
#include <fstream>
#include <iostream>
using namespace std;
typedef unsigned char u8;
int main()
{
fstream f;
u8 ch;
f.open("deneme.txt",ios::out|ios::binary);
f.put(129);
f.close();
return 0;
}
When I write 128 into the put function (which takes type of char value as parameter) I took an € but for 129, it is nothing in the text file. I can't see, can't select. Although the cursor appear at the begining of the file, row,col pointer of the notepad interestingly say 1,2
So, there is something but it is not visible. Also according to tutorials, it was same as far as I remember. Can I write between 0 and 255 without portability issues. In order to ensure about that it writes correctly in binary form in all platforms (compilers/operating systems etc.). The cause of my concern is the char type whose range of value can change from platform to platform. Is there such a portability issue for put function or Do I have to worry about it in long run?
OK, I know what to do about that topic anymore. Thanks everybody trying to help me.
In fact, there are no issue at all. I don't know what OS do you use. But on *nix like OS it is very simple to check that you get what you want. Look at size of file I sure you it will be 1 byte. And if you open it in hex editor you get byte with value 0x81 or 129.
About editors, some modern editor may think that this 129 character is begin of UTF-8 sequence, and it has at least two bytes length and show wrong results. Another not modern editor may think that this is some 8bit local endcoding, but this encoding may not describe character 129, or font used by this editor may not contains such glyph. This is the problems of editors not your program.
My main question is about how you read data from a file that is not of the char data type.
I am writing a file of data from MATLAB as follows:
x=rand(1,60000);
fID=fopen('Data.txt','w');
fwrite(fID,x,'float');
fclose(fID);
Then when I try to read it in C++ using the following code "num" doesn't change.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream fin("Data.txt",ios::in | ios::binary);
if (!fin)
{
cout<<"\n Couldn't find file \n";
return 0;
}
float num=123;
float loopSize=100e3;
for(int i=0; i<loopSize; i++)
{
if(fin.eof())
break;
fin >> num;
cout<< num;
}
fin.close();
return 0;
}
I can read and write file in matlab fine, and I can read and write in c++, but I can't write in matlab and read in c++. The files I write in matlab are in the format I want, but the files in c++ seem to be writing/reading the numbers out at text. How do you read a series of floats in from a file in C++, or what am I doing wrong?
edit: The loop code is messy because I didn't want an infinite loop and the eof flag was never being set.
Formatted I/O using << and >> does indeed read and write numeric values as text.
Presumably, Matlab is writing the floating-point values in a binary format. If it uses the same format as C++ (most implementations of which use the standard IEEE binary format), then you could read the bytes using unformatted input, and reinterpret them as a floating-point value, along the lines of:
float f; // Might need to be "double", depending on format
fin.read(reinterpret_cast<char*>(&f), sizeof f);
If Matlab does not use a compatible format, then you'll need to find out what format it does use and write some code to convert it.
You need to read and write the same format. For that matter, what you have written from Matlab is an unformatted sequence of bytes which may or may not be able read depending on whether you use the same system. You can probably read this unformatted sequence of bytes into a C++ program (e.g. using std::istream::read()) but you shouldn't consider the data to be stored.
To actually store data, you need to be aware of the format the data has. The format can be binary or text but you should be clear about what the bytes mean, in which order they appear, how many there are or how to detect the end if a value, etc.
Using fwrite is not the best idea, because this will write out the data in an internal format, which might or might not be easy to read back in your program.
Matlab has other ways of writing output, e.g. functions like fprintf. Better write out your data this way, then it should be obvious how to read it back into another application.
Just use fprintf(fID, "%f\n", x), and then you should be able to use scanf to read this back in C/C++.