【问题标题】:Writing 16 bits from matrix to a text file, reading them back in differently in C++将 16 位从矩阵写入文本文件,在 C++ 中以不同方式读取它们
【发布时间】:2011-06-23 20:37:31
【问题描述】:

我有一个无符号 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);

    }
}

你猜到为什么会这样吗?

【问题讨论】:

  • q1的数据类型是什么?
  • uint16_t,我已将其 typedef'd 作为一个简短的

标签: c++ image-processing multidimensional-array


【解决方案1】:

您不能按位写入浮点数据并将其作为 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

【讨论】:

  • 啊,哎呀,我只是想看看它会输出什么。但是,第一个值(索引 0,0)完全错误,因此不可能。
  • 我正在写 541.9032 并阅读 40894。我意识到我正在写一个 double 并将其作为 uint16_t 读入..但它不应该忽略额外的精度吗?
  • 不,如果您将其作为原始二进制数据写入,则没有从 double 到 short 的隐式转换,它只是在写入数据。另外,double 表示为 64 位(8 个字节),因此当您将其写出时,您只存储前两个字节并丢失其余字节。
  • 谢谢你,戴夫 - 我决定在写完评论后尝试一下,发现它有效。如此愚蠢的错误...谢谢!
【解决方案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 &lt;&lt; "hello world"(即 @987654325 @ 在那里)。我在需要时选择明确地use arraystream 命名空间,请参阅下面的完整示例。

这是一个完整的可编译示例,通过校验和哈希显示读回的数据确实相同。 不需要 Boost 来使用这些助手。我使用 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;
}

【讨论】:

  • 谢谢!实际上我可能很快就会需要这个。
猜你喜欢
  • 1970-01-01
  • 2012-09-30
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
相关资源
最近更新 更多