Writing 16 bits from matrix to a text file, reading them back in differently in C++
I have a matrix of unsigned 16's which I am writing out to a text file using
void output() {
ofstream myfile;
myfile.open("output.raw", ios::out | ios::binary);
for(int i=0; i< 100; i++) {
for(int j=0; j < 100; j++) {
myfile.write((char*)&r2[i][j], sizeof(uint16_t));
}
}
}
As this is a ".raw" image file, I believe each uint16 should just be written to the file in succession without an开发者_开发百科y sort of breaks (please correct me if I'm wrong about this).
When I read the data back in, the array does not contain the same values as it did going into the text file. I am reading the data back in with:
for(int i=0; i<NUM_COLS; i++) {
for(int j=0; j<NUM_ROWS; j++) {
fread(&q1[j][i], sizeof(uint16_t), 1, fp);
}
}
Any guesses as to why this is happening?
You cannot write floating point data bitwise and read it back as int. You have to convert the float to an integer data type before you write it. Floating point numbers have a totally different binary representation as integer: IEEE_754
for(int i=0; i< 100; i++) {
for(int j=0; j < 100; j++) {
uint16_t val = (uint16_t)r2[i][j];
myfile.write((char*)&val , sizeof(uint16_t));
}
}
Also you read back the values in the wrong order:
fread(&q1[j][i], sizeof(uint16_t), 1, fp);
should be
fread(&q1[i][j], sizeof(uint16_t), 1, fp); // i and j interchanged
Just for fun, I wrote these generic helpers to write arbitrary 2-dimensional arrays to binary streams:
namespace arraystream
{
template <class T, size_t M> std::istream& operator>>(std::istream& is, const T (&t)[M])
{ return is.read ((char*) t, M*sizeof(T)); }
template <class T, size_t M> std::ostream& operator<<(std::ostream& os, const T (&t)[M])
{ return os.write((char*) t, M*sizeof(T)); }
template <class T, size_t N, size_t M> std::istream& operator>>(std::istream& is, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) is >> tt[i]; return is; }
template <class T, size_t N, size_t M> std::ostream& operator<<(std::ostream& os, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) os << tt[i]; return os; }
}
You can use them like so in your code:
char c [23] [5];
float f [7] [100];
uint16_t r2[100][100]; // yes that too
std::ofstream ofs("output.raw", std::ios::binary || std::ios::out);
ofs << c << f << r2;
ofs.flush();
ofs.close();
////
std::ifstream ifs("output.raw", std::ios::binary || std::ios::in);
ifs >> c >> f >> r2;
ifs.close();
The only minor drawback here is that if you were to declare these in namespace std (or use
them all the time), the compiler would try to use these overloads to write std::cout << "hello world"
too (that is a char[12]
right there). I opted to explicitely use
the arraystream
namespace where required, see full sample below.
Here is a complete compilable example showing with a checksum hash that the data read back is indeed identical. Boost is not required to use these helpers. I use boost::random to get a set of random data, boost::hash to do the checksum. You could employ any random generator, and perhaps use an external checksum tool instead.
Without further ado:
#include <fstream>
#include <boost/random.hpp>
#include <boost/functional/hash.hpp>
namespace arraystream
{
template <class T, size_t M> std::istream& operator>>(std::istream& is, const T (&t)[M]) { return is.read ((char*) t, M*sizeof(T)); }
template <class T, size_t M> std::ostream& operator<<(std::ostream& os, const T (&t)[M]) { return os.write((char*) t, M*sizeof(T)); }
template <class T, size_t N, size_t M> std::istream& operator>>(std::istream& is, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) is >> tt[i]; return is; }
template <class T, size_t N, size_t M> std::ostream& operator<<(std::ostream& os, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) os << tt[i]; return os; }
}
template <class T, size_t N, size_t M>
size_t hash(const T (&aa)[N][M])
{
size_t seed = 0;
for (size_t i=0; i<N; i++)
boost::hash_combine(seed, boost::hash_range(aa[i], aa[i]+M));
return seed;
}
int main()
{
uint16_t data[100][100];
{
// make some (deterministic noise)
boost::mt19937 rand(0);
for (int i=0; i<100; i++) for (int j=0; j<100; j++) data[i][j] = rand();
}
{
// write a file
std::ofstream ofs;
ofs.open("output.raw", std::ios::out | std::ios::binary);
using namespace arraystream;
ofs << data;
ofs.flush();
ofs.close();
}
uint16_t clone[100][100];
{
// read a file
std::ifstream ifs;
ifs.open("output.raw", std::ios::in | std::ios::binary);
using namespace arraystream;
ifs >> clone;
ifs.close();
}
std::cout << "data: " << hash(data) << std::endl;
std::cout << "clone: " << hash(clone) << std::endl;
return 0;
}
精彩评论