开发者

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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜