C++ File Operations - c++

As part of an assignment, I need to read data from a binary file which consists of int, char datatypes of data. This binary file is divided into records 96 bytes each. I am trying to reading these 96 bytes into a char buffer and then trying to split them according to info I have. But I am getting nothing when trying to get int values from the buffer. Can you help me in this?
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
int main()
{
char buffer[100];
char *p;
char temp[10];
int val;
fstream ifs,ofs;
ifs.open("write.bin",ios::binary);
if(ifs.read(buffer,96))
{
cout << "READ" << endl;
}
p = buffer;
memcpy(temp,buffer,4);
cout << temp << endl;
val = atoi(temp);
cout << val << endl;
}
I used strncpy also in place of memcpy.
The output is 0 for val and blank for temp.

atoi transforms strings (char arrays) into integers. So something like "42" would return the integer 42. The way your question is written, it sounds like the integers are simply stored as binary in the textfile.
A simple cast of the buffer pointer to the desired type plus a dereference should do:
/* read 96 bytes into char array buffer */
uint32_t your_number = *(uint32_t*)buffer;
cout << your_number << endl;
If you want to use memcpy, there's no need to copy to a char array, you can copy directly to an integer address:
uint32_t your_number;
memcpy(&your_number, buffer, 4);
cout << your_number << endl;
With plain C (not C++) this would be:
uint32_t your_number;
FILE *f = fopen("write.bin", "r");
fread(&your_number, sizeof(uint32_t), 1, f); /* uint32's size is 4 bytes */
fclose(f);
printf("%d\n", your_number);
I chose uint32_t as a data type, because it is guaranteed to have 32 bits/4 bytes – int might, on some platforms/compilers, be of different size.

Unlike C-style functions, read does not return number or bytes read, instead, it returns istream&. So to check the result, call ifs.gcount() after ifs.read().

Related

Reading values from binary file stored in char array with reinterpret_cast (C++)

I am trying to read in a binary file in a known format. I want to find the most efficient way to extract values from it. My ideas are:
Method 1: Read each value into a new char array then get it into the correct data type. For the first 4 byte positive int, I bitshift the values accordingly and assign to an integer as below.
Method 2: Keep the whole file in a char array, then create pointers to different parts of it. In the code below I am trying to point to these first 4 bytes and use reinterpret_cast to interpret them as an integer when I dereference the variable 'bui'.
But the ouput from this code is:
11000000001100000000110000000011
3224374275
00000011000011000011000011000000
51130560
My questions are
why does the endianness get swapped using my method 2 and how do I point to it correctly?
which method is more efficient? I need all of the file, and the file contains other data types too so I will need to write different methods to interpret them if using method 1. I was assuming I could just define different type pointers if using method 2 without doing extra work!
Thanks
#include <iostream>
#include <bitset>
int main(void){
unsigned char b[4];
//ifs.read((char*)b,sizeof(b));
//let's pretend the following 4 bytes are read in representing the number 3224374275:
b[0] = 0b11000000;
b[1] = 0b00110000;
b[2] = 0b00001100;
b[3] = 0b00000011;
//method 1:
unsigned int a = 0; //4 byte capacity
a = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
std::bitset<32> xm1(a);
std::cout << xm1 << std::endl;
std::cout << a << std::endl;
//method 2;
unsigned int* bui = reinterpret_cast<unsigned int*>(b);
std::bitset<32> xm2(*bui);
std::cout << xm2 << std::endl;
std::cout << *bui << std::endl;
}

C++ reading binary data to struct

I am currently reading a binary file that i know the structure of and i am trying to place into a struct but when i come to read off the binary file i am finding that when it prints out the struc individually it seems to come out right but then on the fourth read it seems to add it onto last member from the last read.
here the code which probably make's more sense than how i am explaining it:
Struc
#pragma pack(push, r1, 1)
struct header
{
char headers[13];
unsigned int number;
char date[19];
char fws[16];
char collectversion[12];
unsigned int seiral;
char gain[12];
char padding[16];
};
Main
header head;
int index = 0;
fstream data;
data.open(argv[1], ios::in | ios::binary);
if(data.fail())
{
cout << "Unable to open the data file!!!" << endl;
cout << "It looks Like Someone Has Deleted the file!"<<endl<<endl<<endl;
return 0;
}
//check the size of head
cout << "Size:" << endl;
cout << sizeof(head) << endl;
data.seekg(0,std::ios::beg);
data.read( (char*)(&head.headers), sizeof(head.headers));
data.read( (char*)(&head.number), sizeof(head.number));
data.read( (char*)(&head.date), sizeof(head.date));
data.read( (char*)head.fws, sizeof(head.fws));
//Here im just testing to see if the correct data went in.
cout<<head.headers<< endl;
cout<<head.number<< endl;
cout<<head.date<< endl;
cout<<head.fws<< endl;
data.close();
return 0;
Output
Size:
96
CF001 D 01.00
0
15/11/2013 12:16:56CF10001001002000
CF10001001002000
for some reason the fws seems to add to head.date? but when i take out the line to read head.fws i get a date that doesn't have anything added?
i also know thier more data to get for the header but i wanted to check the data up to what i have written is correct
cheers
1. Your date is declared as:
char date[19];
2. Your date format is exactly 19-characters long:
15/11/2013 12:16:56
3. And you print it this way:
cout<<head.date
Shortly speaking, you try to print fixed char[] using its address, which means, that it will be interpreted as null-terminated c-string. Is it null-terminated? No.
To solve this problem, declare date as:
char date[20];
And after you fill it, append null terminator:
date[19] = 0;
It applies to all members, that will be interpreted as string literals.
You have char date[19] filled with 15/11/2013 12:16:56 which is exactly 19 valid characters. This leaves no space for a terminating null and so doing cout << head.date outputs your 19 valid characters and then a load of garbage.

Using memcpy trying to copy one struct into a char[] buffer

#define ECHOMAX 100
struct tDataPacket
{
int iPacket_number;
char sData[ECHOMAX];
};
int main () {
tDataPacket packet;
packet.iPacket_number=10;
strcpy(packet.sData,"Hello world");
char buffer[sizeof(tDataPacket)];
memcpy(buffer,&packet.iPacket_number,sizeof(int));
memcpy(buffer+sizeof(int),packet.sData,ECHOMAX);
std::cout<<"Buffer = "<<buffer<<"END";
return 0;
}
In the above code I am trying to pack my structure in a char[] buffer so that I can send it to a UDP socket. But the output of the program is "" string. So nothing is getting copied to 'buffer'. Am I missing anything??
When you copy the int, at least one of the first "n" characters of the buffer will be zero (where "n" is the size of an int on your platform). For example for a 4-byte int:
x00 x00 x00 x0a or x0a x00 x00 x00
Depending on the endianness of your processor.
Printing out the zero will have the effect of terminating the output string.
You have no code to sensibly print the contents of the buffer, so you are expecting this to work by magic. The stream's operator << function expects a pointer to a C-style string, which the buffer isn't.
It's "" because int iPacket_number is probably laid out in memory as:
0x00 0x00 0x00 0x0a
which is an empty string (nul-terminator in the first character).
Firstly you probably want some sort of marshalling so that the on-the-wire representation is well established and portable (think endian differences between platforms).
Secondly you shouldn't need to "print" the resulting string; it makes no sense.
Thirdly you want unsigned char, not (signed) char.
You can't print an integer as text, because it's not text.
You will need to do a loop (or something like that) to print the actual contents of the buffer:
std::cout << "Buffer=";
for(size_t i = 0; i < sizeof(tDataPacket); i++)
{
std::cout << hex << (unsigned int)buffer[i] << " ";
if ((i & 0xf) == 0xf) std::cout << endl; // Newline every 16.
}
std::cout << "END" << endl;
You can do this but it's not really relevant to display binary data like that:
std::cout<<"Buffer = "; for each (auto c in buffer)
{
std::cout<< c;
}
std::cout <<"END";

The sizeof several casts

Why does the function sizeof not return the same size when its getting used on the struct itself?
I need to cast it because of a winsock program that im working on.
Thanks for any help, true.
#include <iostream>
#include <string>
using namespace std;
struct stringstruct
{
string s1;
string s2;
};
int main()
{
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
getchar();
return 0;
}
the example above outputs
4
1
4
64
sizeof will tell you the size of the given expression's type. In both the sizeof(NX) and sizeof(&ss), the result is 4 because pointers on your machine take up 4 bytes. For sizeof(*NX), you are dereferencing a char*, which gives you a char, and a char takes up 1 byte (and always does), so you get the output 1. When you do sizeof(ss), ss is a stringstruct, so you get the size of a stringstruct, which appears to be 64 bytes.
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
I'm pretty sure that any of these casts are pretty meaningless. NX will point at the beginning of your struct. Inside the struct are two objects of type string, which in turn have pointers pointing to the data they were initialized with "123" and "abc" respectively. sizeof(*NX) is just that - size of a char, and sizeof(NX) is indeed the size of a pointer. sizeof(ss) is the size of your two string members (and any padding added by the compiler) - and sizeof(&ss) is the size of a pointer to a stringstruct.
Now, I expect what you REALLY want is a way to send your data, "123" and "abc" as two separate strings over a network. None of the above will help you do that, since even if sizeof(ss) gives you the size of the data structure you want to send, the string values are not within that structure [1]. What you really need is something calls serialization - something that writes out your strings as separate elements as text/string.
Something like this would work:
struct stringstruct {
string s1;
string s2;
string to_string()
}
string stringstruct::to_string()
{
string res = s1 + " " + s2;
return res;
}
Then use to_string like this:
string temp = ss.to_string();
const char *to_send = temp.c_str();
int send_len = temp.length();
... send the string `to_send` with number of bytes `send_len`.
[1] There is an optimization where std::string is actually storing short strings within the actual class itself. But given a sufficiently long strong, it won't do that.
A pointer is of size 4(in your case seems to be 32 bit) no matter what it points. Size of the object itself on the other hand returns the real number of bytes that an object of that structure takes.

Reading/Writing integer values on a string object

I have the contents of a file assigned into a string object. For simplicity the file only has 5 bytes, which is the size of 1 integer plus another byte.
What I want to do is get the first four bytes of the string object and somehow store it into a valid integer variable by the program.
Then the program will do various operations on the integer, changing it.
Afterward I want the changed integer stored back into the first four bytes of the string object.
Could anyone tell me I could achieve this? I would prefer to stick with the standard C++ library exclusively for this purpose. Thanks in advance for any help.
The following code snippet should illustrate a handful of things. Beware of endian differences. Play around with it. Try to understand what's going on. Add some file operations (binary read & write). The only way to really understand how to do this, is to experiment and create some tests.
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[]) {
int a = 108554107; // some random number for example sake
char c[4]; // simulate std::string containing a binary int
*((int *) &c[0]) = a; // use casting to copy the data
// reassemble a into b, using indexed bytes from c
int b = 0;
b |= (c[3] & 0xff) << 24;
b |= (c[2] & 0xff) << 16;
b |= (c[1] & 0xff) << 8;
b |= c[0] & 0xff;
// show that all three are equivalent
cout << "a: " << a << " b: " << b
<< " c: " << *((int *) &c[0]) << endl;
return 0;
}
If you are reading into std::string from that file any zero byte would signal end of the string, so you might end up with a string that is shorter then 5 bytes. Take a look here for how to do binary I/O with C++ streams.