How to read/write unsigned array to ifstream/ostream in c++? - c++

I have below code :
/*write to file*/
std::basic_ofstream<unsigned short> out(path, std::ios::out);
unsigned short *arr = new unsigned short[500];
for (int i = 0; i < 500; i++)
{
arr[i] = i;
}
out.write(arr, 500);
out.close();
/*read from file*/
unsigned short * data = new unsigned short[500];
std::basic_ifstream<unsigned short> rfile(path);
rfile.read(data, 500);
rfile.close();
Simply i write a unsigned short array to file then i read that but read values are right until index 25 in array and after that the values are 52685.
Where is the problem?

First of all, don't use the template parameter of basic_ofstream with a non character type (i.e. char, wchar_t, char16_t or char32_t). For the most part, just use ofstream (and ifstream for input).
The fact that your input stops after the 25th character is actually a clue that you are probably on Windows, where ASCII character 26, the Substitute character, is used to indicate end of file for text streams. You are trying to read and write binary data though, so you need to open your file with the binary flag.
/*write to file*/
std::ofstream out(path, std::ios::binary);
unsigned short *arr = new unsigned short[500];
for (int i = 0; i < 500; i++) {
arr[i] = i;
}
out.write((char const*)arr, 500 * sizeof(arr[0]));
out.close();
/*read from file*/
unsigned short * data = new unsigned short[500];
std::ifstream rfile(path, std::ios::binary);
rfile.read((char*)data, 500 * sizeof(data[0]));
rfile.close();
Also interesting to note, 52685, in hexadecimal is 0xCDCD. This is the value which Visual C++ (and maybe some other compilers) uses to fill uninitialized memory in debug mode. Your array isn't receiving this value from the file, this is the value which was inserted there when your memory was allocated.

Related

Using fstream to read from a binary file and store the results in a vector

I'm working on a project for my CS202 class. I have a supplied binary file of unknown size called data.dat and need to read integers (which I don't know in advance) from the file and store them in a properly sized vector. I have to use fstream() for the filestream and I have to use the reinterpret_cast<char *>() for the conversion. My code looks like this:
fstream filestream2;
//reading binary data from supplied data.dat file
filestream2.open("data.dat", ios::in | ios::binary);
vector<int> v;
filestream2.seekg(0, filestream2.end);
long length = filestream2.tellg();
v.resize(length);
filestream2.read(reinterpret_cast<char *>(&v[0]), length);
for(int num = 0; num < length; num++)
{
cout << v[num] << " ";
}
In theory, the vector should hold all of the integers from the file and print them to stdout, but my output is simply about 50,000, 0s followed by program exited with exit code 0
I'm relatively new to C++ syntax and libraries and I just cannot figure out what I'm doing wrong for the life of me.
Thanks in advance.
When you use
filestream2.seekg(0, filestream2.end);
long length = filestream2.tellg();
you get the number of characters in the file, not the number of items in the vector. Consequently, you will need to use length/sizeof(int) when you want use the size of the vector.
v.resize(length);
is incorrect. It needs to be
v.resize(length/sizeof(int));
and
for(int num = 0; num < length; num++)
{
cout << v[num] << " ";
}
is incorrect. It needs to be
for(int num = 0; num < length/sizeof(int); num++)
{
cout << v[num] << " ";
}
You said that "you don't know in advance" which kind of data ( size of data) is stored in file. The main problem is to identify size of data and its datatype. So what can you do is, create custom formate file.
For ex.
1st byte of file will indicate type of data, (ex. I for integer, F for float, U for unsigned int, C for char, S for char* (string) so on)
Next 4 bytes will be size of data ( required only for char* so it is optional)
After that actual date will be started.
So data will be in file like
Cabcdefghijk
Here 1st byte is C so data will be char. So need to create vector of char type.
Next data size :
fstream.seekg(0, fstream.end);
long length = fstream.tellg(); // length : 12
length -= 1; // 1st byte is indecator // length : 11
// length -= 4; // Optional : if you had write size of data
length = length / sizeof( char); // sizeof( int) or sizeof( flot) or written in file.
// so in our case length will be 11;
Now you have data type and size of data, so create or resize vector accordingly.

Write hex array to the file as string in C/C++

This is a frequently question but I could not find appropriate answer.
I have a char array containing HEX values. I need to write this array in a text file "as a string".
My understanding of HEX not being stored in the files (looked garbage data) was flawed. In Hex editor I could see the data.
My Hex array is actually integer array and not characters. This I need to take into consideration.
I tried this:
FILE * out = fopen(out_file_name, "w");
char *in = (char*)malloc(sizeof(char) * num_encryption * 16);
....
fwrite(in, sizeof(char), num_encryption*16 + 1, out);
I also tried stream but it again prints garbage in text files.
The in array contains the HEX strings like this: 21c169ea622e7d52ecd35423f4c3c9f4, and there are 32 lines (num_encryption=32) in total.
I also tried something like this:
std::ofstream outfile(argv[21]);
if(outtfile.is_open()){
//outtfile.write(wo, sizeof(char)*(num_encryption*16+1));
for(int k = 0; k < num_encryption; k++){
for(int j = 0; j < 16; ++j){
outfile << static_cast<unsigned char>(wo[j + k*16] & 0xff);
}
outtfile << std::endl;
}
}
Even the commented part did not work properly.
Any suggestions?
Solution
I just redirected the output (which was fine) to the file:
FILE * out = fopen(out_file_name, "w");
for(int k = 0; k < num_encryption; k++){
for(int j = 0; j < 16; ++j){
fprintf(outfile, "%02x", wo[j + k*16] & 0xff);
}
fprintf(outfile, "\n");
}
fclose(outfile);
I am not sure if this is the most elegant solution,but it works for me. If you know anything better then please add here.
If the question is about C++ also, let me give you advice on how to use features superseded by C++. You are using C-style features.
You should use iostreams. Avoid malloc, use new, but, even better, use a vector<char> or unique_ptr<char[]> directly. In this case I will use unique_ptr<char[]> since it seems you do not need to resize the array. I assume you want to write a binary file below.
//I assume you want a binary file
std::ostream file("myfile.txt", std::ios::binary);
std::unique_ptr<char []> in = std::unique_ptr<char []>(new char[num_encryption * 16]);
if (file)
file.write(in.get(), sizeof(char) * num_encryption * 16);
If you want, instead, write text data in hex, open the file in text mode:
std::ostream file("myfile.txt"); //Note, no std::ios::binary
...
file >> std::hex >> std::noshowbase; //Write in hex with no base
std::copy(in.get(),
in.get() + num_encryption * 16,
std::ostream_iterator<char>(file)); //Write one char at a time, in hex, with no base
WARNING: Not tested, just shown the idea on how to write binary or formatted hex text, char by char.

C++ Writing Binary Dump and Writing to Binary from Dump

I am stumped and need some assistance.
In one of my programs, I am implementing some code so that I can take a program on Windows and essentially do a hexdump (what you see in hex editors) where I convert it to binary and write that to a .txt document. I just recently got that half figured out. The other half of the code is to rebuild an object that has been dumped to binary in .txt file into the original object. This should work for all objects in general and not just rebuilding one certain object.
Partial Code for Dumping Part:
//Rip Program to Binary
streampos size; //Declare size variable
unsigned char* memblock; //Holds input
ifstream input; //Declare ifstream
ofstream output("output.txt", ios::out|ios::binary); //Specify ofstream
input.open("sparktools.bin", ios::in|ios::binary|ios::ate); //Open input file and move to the end of it
size = input.tellg(); //Store current location as file length
memblock = new unsigned char [size]; //Declare the input holder with array size as length of file
input.seekg (0, ios::beg); //Return to beginning of file
input.read((char*)memblock, size); //Read each character of the input file until end of file
for (int i=0; i<size; i++) //For each character until end of file:
{
std::bitset<sizeof(char) * CHAR_BIT> binary(memblock[i]); //Set bitset<1> to essentially convert to a binary char array
output << binary; //Output from binary variable created
}
input.close();
output.close();
delete[] memblock;
Partial Code for Rebuilding Part:
//Restore Ripped Binary To Program
int size; //Holds length of input document
unsigned char* memblock; //Holds input
ifstream input; //Declare ifstream
ofstream output("Binary.bin", ios::out|ios::binary); //Specify ofstream
input.open("Binary.txt", ios::in|ios::binary|ios::ate); //Open input file and move to the end of it
size = input.tellg(); //Store current location as file length
input.seekg(0, ios::beg); //Return to beginning of file
memblock = new unsigned char [size]; //Declare the input holder with array size as length of file
input.read((char*)memblock, size); //Read each character of the input file until end of file
for (int i=0; i<size; i++) //For each character until end of file:
{
output.write((char*) &memblock[i], size); //Write each char from the input array one at a time until end of file to the output binary
}
input.close();
output.close();
delete[] memblock;
I am testing the capabilities on an image. The original filesize is 10 KB. When dumped, the .txt file is 76 KB and the contents match what shows in a hex editor.
When I am rebuilding from the binary dump, the filesize will not go back to 10 KB. When I up the bitset number, the file size increases. However, at bitset<1> it stays at 76 KB. From my conclusion, I essentially need bitset <0.125> to reduce the filesize from 76KB back down to 10 KB and the numbers should match up and it can simply be renamed from .bin to .whatever-it-originally-was and function correctly. However I don’t think bitset goes below 1.
Code I have tried:
43555 KB: output.write((char*)&memblock[i], size);
0 KB: output.write((char*)memblock[i], size);
43555 KB: output.write((const char*)&memblock[i], size);
43555 KB: output.write(reinterpret_cast<const char*>(&memblock[i]), size);
43555 KB: output.write(reinterpret_cast<char*>(&memblock[i]), size);
76 KB: output << memblock[i];
When I do these simple checks:
cout << memblock[i];
cout << size;
I am seeing that all of the input has been read in and is identical to what is in the file. The size variable is correct at 77296.
From doing some guesswork, I think I need to do something with bitset or else manually convert from bits back to bytes, convert, and then pass that value on to accomplish this. Am I on the right path or is there a better/easier way/something wrong in my code? Thanks in advance for the help!
As far as I can tell the problem is the bit order in the dump of the bitset, the disk dump from the first fragment of code:
11001010
means that the first bit is the most significant of the byte, so to decode this you should do in the loop something like this (tested):
unsigned char *p = memblock;
//For each character until end of file:
for (int i=0; i<size/8; i++)
{
uint8_t byte = 0;
for (int j = 7; j >= 0; j--)
if (*p++ == '1')
byte |= (1 << j);
output.write((char*) &byte, 1);
}
Note that you cycle size/8 since every 8 chars encode a byte and the fact that the inner loop iterates from 7 to 0 to reflect the fact that the first bit is the more significant.

Write byte to ofstream in C++

I have char array, and i want to write it to txt file, but in bytes.
ofstream sw("C:\\Test.txt");
for(int i = 0; i < 256; i++)
{
sw << (byte)myArray[i];
}
This will write chars into the file, but i want to write bytes. If there is char 'a' i want to write '97'. Thank you.
To write a byte or a group of bytes using std::fstream or std::ofstream, you use the write() function: std::ostream::write()
const int ArraySize = 100;
Byte byteArray[ArraySize] = ...;
std::ofstream file("myFile.data");
if(file)
{
file.write(&byteArray[0], ArraySize);
file.write(&moreData, otherSize);
}
ofstream sw("C:\\Test.txt");
for(int i = 0; i < 256; i++)
{
sw << (int)myArray[i];
}
This will convert a char 'a' to an int(or byte) value 97.

Read binary file and convert to binary string

I am trying to write a function that reads specified number of bytes from a binary file and converts them into a string of 1's and 0's. What is the easiest way to do that.
File is in BigEndian.
string ReadBytesFromFile(int size)
{
string result;
ifstream file ("example.bin", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
//need to convert memblock to binary string
result = GetBinaryString(memblock);
delete[] memblock;
}
return result;
}
Call itoa() passing 2 as the radix. Make sure you don't overrun your buffer!
Note: This isn't part of any C or C++ standard so be warned it is not portable. But you asked for ease rather than portability!
Take a byte at a time, and shift the bits off one by one.
Something like:
std::ostringstream ss;
for (int i=0; i<size; ++i) {
char byte = memblock[i];
for (int j=0; j<8; ++j) {
ss << byte & 1;
byte = byte << 1;
}
}