【问题标题】:How to write a 2D vector into a binary file?如何将二维向量写入二进制文件?
【发布时间】:2011-11-19 11:02:26
【问题描述】:

大家! 我有一个充满无符号字符的二维向量。现在我想将其内容保存到二进制文件中:

std::vector<std::vector<unsigned char> > v2D(1920, std::vector<unsigned char>(1080));

// Populate the 2D vector here
.....

FILE* fpOut;

// Open for write
if ( (err  = fopen_s( &fpOut, "e:\\test.dat", "wb")) !=0 )
{   
   return;
}

// Write the composite file
size_t nCount = 1920 * 1080 * sizeof(unsigned char);
int nWritten = fwrite((char *)&v2D[0][0], sizeof(unsigned char), nCount, fpOut);

// Close file
fclose(fpOut);

但是,当我阅读 test.dat 时,填写一个新的 2D 向量,并将其条目与旧的进行比较。我发现写的内容和原来的不一样。为什么?我的 write 语句有什么问题?你能告诉我如何以正确的方式将二维向量写入二进制文件吗?非常感谢!

    #define LON_DATA_ROWS 1920
    #define LON_DATA_COLS 1080

    std::vector<std::vector<float> > m_fLon2DArray(LON_DATA_ROWS, std::vector<float>(LON_DATA_COLS));

    std::ifstream InputFile;

    int nSizeOfLonData = TOTAL_LON_ELEMENTS * sizeof(float);

    std::vector<char> vLonDataBuffer(nSizeOfLonData);

    // Open the file
    InputFile.open(m_sNorminalLonLatFile.c_str(), ios::binary);

    // Unable to open file pszDataFile for reading
    if ( InputFile.fail() )
       return false;

    // Read longitude data buffer
    InputFile.read(&vLonDataBuffer[0], nSizeOfLonData);

    // Close the file object
    InputFile.close();

    // Populate the longitude 2D vector
    for (unsigned i = 0; i < LON_DATA_ROWS; i++) 
    {   
        memcpy(&m_fLon2DArray[i][0], &vLonDataBuffer[(i * LON_DATA_COLS) * sizeof(float)], LON_DATA_COLS * sizeof(float));
    }

    // Some operation put here

    // Write the results to a binary file

【问题讨论】:

  • 长话短说:这不是二维向量,而是向量的向量。 :)
  • 为了最好地使用二维数组,您可以汇总自己的小类(包装单个向量并支持 x,y 访问操作),代码应该少于 1 屏幕。或者,如果你喜欢 Boost,你可以使用 boost::multi_array。

标签: c++ vector 2d


【解决方案1】:

这是错误的。 v2D 包含的数据不在连续内存中。但是,v2D(它是一个向量)的每个元素都在连续的内存中。即v2D[i]包含的数据在连续内存中。

所以你应该这样做:

int nWritten = 0;
for(size_t i = 0; i < v2D.size(); i++ )
{
   if ( v2D[i].size() > 0 )
     nWritten += fwrite(&v2D[i][0], sizeof(unsigned char), v2D[i].size(), fpOut);
}

或者你可以使用 C++ IOStream 作为:

std::ofstream file("E:\\test.data", std::ofstream::binary);
for(size_t i = 0; i < v2D.size(); i++ )
{
    if ( v2D[i].size() > 0 )
    {
       const char* buffer = static_cast<const char*>(&v2D[i][0]);
       file.write(buffer, v2D[i].size());
    }
}

【讨论】:

  • 谢谢!但结果和我的一样。
  • @GoldenLee:现在,您需要告诉我们文件是什么,您期望什么?
  • 亲爱的 Nawaz:我在转换 2D 矢量元素时可能会出错。事实上,我的二维向量的所有元素都分配在一个连续的内存块中。我只是在逻辑上将一维向量拆分为二维向量以方便访问。非常感谢!
  • @GoldenLee:向量分配它自己的内存。你错了;不保证向量的向量具有连续的内存。发布更多代码和其他信息。
  • 你的解释是对的。实际上,这里发布的代码 sn-p 仅用于演示目的。在我的产品程序中,我的 2D 矢量保存图像数据。我使用我的方法和您的方法进行了测试。我得到了同样的照片!他们没事!这只是一个巧合。我不知道为什么。
【解决方案2】:

内存中的向量向量看起来不是这样的:

|---------|---------|---------|---------|...   (where "-" is one element)
     0         1         2         3        

而是像这样:

|->0x48267a70|->0x894753b2|->0xb8cc92f0|->0x22d8cc71|...

(每个向量都有一个指向其内部数据的指针,当增长超过已分配的内存量时,该指针将被重新分配)。

您所做的是获取第一个向量的内部缓冲区的地址,并在耗尽其元素后对其进行过度索引。这是未定义的行为,这就是为什么您的文件中有内存垃圾(但您有相同的机会使程序崩溃)。

您可以通过迭代将存储的向量一一写入文件。采用更惯用的 C++ 风格:

std::ofstream outfile("e:\\test.dat", std::ios::binary | std::ios::out);
if (!outfile.is_open()) ... // handle error

for (std::vector<std::vector<unsigned char> >::iterator it = v2D.begin();
     it != v2D.end();
     ++it)
{
    outfile.write(&it->front(), it->size() * sizeof(unsigned char));
}

或者,在 C++11 中,上面将如下所示:

for (auto& it : v2D) 
{
    outfile.write(&it.front(), it.size() * sizeof(unsigned char)); 
}

在这两种情况下,都应该处理ios_base::failure 异常。

【讨论】:

  • 当你使用 C++11 的 range-based for 循环时,循环变量将是 std::vector&lt;unsigned char&gt;,而不是迭代器,这意味着 it-&gt;front() 应该实际上是it.front()(同样是it.size())。
  • 另外,使用引用避免复制:for (auto &amp; v : v2D) { outfile.write(&amp;v.front(), v.size() * sizeof(unsigned char)); }
  • @Tamás Szelei:非常感谢。先生/女士。 Nawaz 和您好心地建议我应该使用外循环来确保将 2D 矢量正确写入文件。我将纠正我对vector和其他STL容器的存储(自我管理)的误解。谢谢!
【解决方案3】:

做二维矩阵主要有两种方式: 通过定义一个 n*m 内存区域或通过具有指向 m 个向量的 n 个指针的列表。你有后者的变体。

您正在做的是将矢量数据列表写入文件...您的数据不连续,因此您正在将“矢量”类实例数据写入文件。

您可以将每个子向量一个一个地写入,或者使用 1920 * 1080 的单个向量,并像您一样写入文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    • 2012-12-14
    • 2012-12-25
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 2012-12-14
    相关资源
    最近更新 更多