Запись 16 битов из матрицы в текстовый файл, чтение их по-разному в C ++ - PullRequest
4 голосов
/ 24 июня 2011

У меня есть матрица без знака 16, которую я записываю в текстовый файл, используя

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

}

Поскольку это файл изображения ".raw", я считаю, что каждый uint16 должен просто записываться в файл подряд без каких-либо разрывов (пожалуйста, исправьте меня, если я ошибаюсь).

Когда я читаю данные обратно, массив не содержит те же значения, что и в текстовом файле. Я читаю данные обратно с:

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);

    }
}

Есть предположения, почему это происходит?

Ответы [ 2 ]

4 голосов
/ 24 июня 2011

Вы не можете записывать данные с плавающей запятой по битам и читать их как int.Вы должны преобразовать число с плавающей точкой в ​​целочисленный тип данных, прежде чем писать его.Числа с плавающей запятой имеют совершенно другое двоичное представление в виде целого числа: 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));
    }
}

Также вы читаете значения в неправильном порядке:

fread(&q1[j][i], sizeof(uint16_t), 1, fp);

должно быть

fread(&q1[i][j], sizeof(uint16_t), 1, fp); // i and j interchanged
2 голосов
/ 24 июня 2011

Ради интереса я написал следующие универсальные помощники для записи произвольных 2-мерных массивов в двоичные потоки:

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

Вы можете использовать их как в своем коде:

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();

Единственным незначительным недостатком здесь является то, что если бы вы объявляли их в пространстве имен std (или use их все время), компилятор попытался бы использовать эти перегрузки и для записи std::cout << "hello world" (то есть char[12] прямо там). Я решил явно use пространство имен arraystream, где это необходимо, см. Полный пример ниже.

Вот полный скомпилированный пример, показывающий с помощью хэша контрольной суммы, что считанные данные действительно идентичны. Повышение не требуется для использования этих помощников. Я использую boost :: random, чтобы получить набор случайных данных, boost :: hash, чтобы выполнить контрольную сумму. Вы можете использовать любой генератор случайных чисел, и, возможно, вместо этого использовать внешний инструмент контрольной суммы.

Без лишних слов:

#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;
}
...