You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++使用ofstream保存TGA文件,第二次调用相同函数生成的文件更大是什么原因?

C++ std::ofstream保存固定大小数组生成的文件大小异常问题

编辑:提问17分钟后问题已解决。
问题原因:我没有以二进制模式打开文件,Windows系统在非二进制模式下处理文件时会额外添加字节。


问题背景

我编写的SaveToFile函数代码如下,其中counter变量仅用于调试,无实际业务功能:

template<uint32_t ArrayLength>
void SaveToFile(std::shared_ptr<std::array<uint8_t, ArrayLength>> TGA, std::string name) {
    std::ofstream outputFile;
    outputFile.open("hardcoded folder path because I am lazy" + name + ".tga");
    int counter = 0;
    for (uint8_t& pixel : *TGA) {
        outputFile << pixel;
        counter++;
    }
    outputFile.close();
}

连续两次调用该函数的代码如下:

std::shared_ptr<std::array<uint8_t, 14422>> TGA = sim.GetTGAByteList();
SaveToFile(TGA, "test");

//sim.Step(16); 
sim.Draw();
// 其余Draw调用已注释
    
TGA = sim.GetTGAByteList();
assert(TGA->size()==14422);
SaveToFile(TGA, "test2");

TGA数组的大小固定为14422,sim.Draw()仅修改TGA数组内存储的数据,不会改变数组长度,这一点也可从后续的assert断言得到验证。用counter变量调试时,逐行步进函数发现每次循环都刚好执行14422次,每次写入1字节。

异常现象

第一次保存的文件大小为14422字节,第二次保存的文件却达到了14583字节。就算传入全新的shared_ptr调用SaveToFile也无法解决该问题。调用sim.Draw()的次数越多,生成的文件就越大,但使用的是固定大小的数组,理论上不应该出现该问题,这些额外的字节是从哪来的?

如果注释掉sim.Draw()调用,无论怎么操作都无法复现该问题。

以下是Draw()函数的实现,其中pixel_data对应TGA数组的最后14400字节:

void Draw(uint8_t configflags = 0)
{
    if ((configflags & 0b00000001) == 0) {
        for (uint32_t i = 0; i < (*pixel_data).size(); i++) {
            uint64_t sum_of_neighbours = 0;

            bool left_edge = i % texture_width == 0;
            bool right_edge = i % texture_width == texture_width - 1;
            bool top_edge = i < texture_width;
            bool bottom_edge = i >= (texture_width * (texture_height - 1));

            if (!top_edge && !left_edge) //top left
                sum_of_neighbours += (*pixel_data)[i - texture_width - 1];
            if (!top_edge)  //top
                sum_of_neighbours += (*pixel_data)[i - texture_width] * 2;
            if (!top_edge && !right_edge) //top right
                sum_of_neighbours += (*pixel_data)[i - texture_width + 1];

            if (!bottom_edge && !left_edge) //bottom left
                sum_of_neighbours += (*pixel_data)[i + texture_width - 1];
            if (!bottom_edge) //bottom
                sum_of_neighbours += (*pixel_data)[i + texture_width] * 2;
            if (!bottom_edge && !right_edge) //bottom right
                sum_of_neighbours += (*pixel_data)[i + texture_width + 1];

            if (!left_edge) //left
                sum_of_neighbours += (*pixel_data)[i - 1] * 2;
            if (!right_edge)    //right
                sum_of_neighbours += (*pixel_data)[i + 1] * 2;

            //self
            sum_of_neighbours += (*pixel_data)[i] * 4;

            (*pixel_data)[i] = sum_of_neighbours / 16;
        }
    }

    if ((configflags & 0b00000010) == 0) {
        for (Agent& agent : agents) {
                uint32_t index = floor(agent.position.x);
                index += floor(agent.position.y) * texture_width;
                (*pixel_data)[index] = -1;
            }
        }
    }

就算把SaveToFile()中的循环硬编码为仅执行14422次,还是会生成大小错误的文件,修改保存的文件名也无法解决问题。


问题原理与修复方案

Windows系统下文件流默认以文本模式打开,此时流会自动将字节0x0A(换行符\n)替换为0x0D 0x0A(回车换行\r\n)的双字节序列,每遇到一次就多写入1字节。第一次生成的TGA数据中没有0x0A字节,所以文件大小和数组大小一致;调用Draw()之后数组内生成了0x0A字节,调用次数越多出现的0x0A越多,最终文件大小就会超出数组原始大小。

修复方法为打开文件时指定std::ios::binary二进制模式,修改open调用的代码即可:

outputFile.open("hardcoded folder path because I am lazy" + name + ".tga", std::ios::binary | std::ios::out);

二进制模式下流不会对写入的字节做任何转换,写入的字节数和数组大小会完全一致。


内容的提问来源于stack exchange,提问作者Jac O' B GmbH und co. KG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 13:15:07