lakshitha
lakshitha

Reputation: 91

Reading bytes one by one from binary file

this is my question, i want to open a .jpg file and write each byte as a decimal number (0-255) separated with a comma, into another .txt file. now it should be able to build the .jpf file again using that txt file. this is how i tried to do it.

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
long x;
char *s;

ifstream ifs("image.jpg",ios::binary);
ifs.seekg(0,ios::end);
x=ifs.tellg();
ifs.seekg(0,ios::beg);

s=new char[x];
ifs.read(s,x);
ifs.close();

ofstream is("image.txt");

for(int i=0;i<x;i++){
is<<(unsigned int)s[i]<<",";
}

now this program creats image.txt with decimal numbers as follows, 4294967295,4294967256,4294967295,4294967264,0,16,74,70,73,70,0,1,...... here some numbers seems to be 4bytes long, s[i] refers only one byte, so how can (int)s[i] return a large number than 255. please can some one help me on this.... thanks..

Upvotes: 2

Views: 9035

Answers (1)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361722

It seems on your machine char is signed. So when you cast a negative number to unsigned int, you get a big value. The big values in the output are negative values when representing them using char. Note that when char is signed, its value can be -128 to 127 but a byte can be between 0 to 255. So any value greater than 127 would become negative between the range -128 to -1.

Use unsigned char as:

unsigned char *s;

Or do this:

is<< static_cast<unsigned int> (static_cast<unsigned char>(s[i]) )<<",";
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                casting to unsigned char first
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               then casting to unsigned int 

That is, cast first char to unsigned char, then to unsigned int.


Well that is all about the issue you're facing. Now some notes on style and idioms. In C++, you should avoid using new as much as possible. In your case, you can use std::vector as:

//define file stream object, and open the file
std::ifstream file("image.jpg",ios::binary);

//prepare iterator pairs to iterate the file content!
std::istream_iterator<unsigned char> begin(file), end;

//reading the file content using the iterator!
std::vector<unsigned char> buffer(begin,end);

The last line reads all the data from the file into buffer. Now you can print them as:

std::copy(buffer.begin(), 
          buffer.end(), 
          std::ostream_iterator<unsigned int>(std::cout, ","));

For all these to work, you need to include the following headers in addition to what you have already added in your code:

#include <vector>     //for vector
#include <iterator>   //for std::istream_iterator and std::ostream_iterator
#include <algorithm>  //for std::copy

As you can see, this idiomatic solution doesn't use pointer and new, neither does it use cast!

Upvotes: 14

Related Questions