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

C++读取PNG文件转十六进制数据错误问题求助

问题:PNG文件转十六进制输出异常

我编写了一个C++程序,读取PNG文件并将其数据转换为十六进制写入新文件。程序能运行,但输出内容存在错误(例如出现ffffffff这类异常值)。

我的代码

#include <iostream>
#include <fstream>

int main()
{
    std::ofstream newImage("gradient-test.txt");
    std::fstream Image("rainbow-gradient-test.png");
    Image.seekg(0, std::iostream::end);
    int size = Image.tellg();

    for (int target = 0; target <= size; target += 1)
    {
        Image.seekg(target, std::iostream::beg);
        int color = Image.peek();
        newImage << std::hex << color;
        newImage << " ";
    }
    newImage.close();
    return 0;
}

生成的gradient-test.txt内容

89 50 4e 47 a a ffffffff a 0 0 0 d 49 48 44 52 0 0 0 80 0 0 0 44 8 2 0 0 0 c6 25 aa 3e 0 0 0 c2 49 44 41 54 78 5e ed d4 81 6 c3 30 14 40 d1 b7 34 dd ff ff 6f b3 74 56 ea 89 12 6c 28 73 e2 aa 34 49 3 87 d6 fe d8 7b 89 bb 52 8d 3b 87 fe 1 0 80 0 0 10 0 0 2 0 40 0 0 8 0 0 1 0 20 0 0 4 0 80 0 0 10 0 0 2 0 40 0 0 8 0 0 1 0 20 0 0 0 d4 5e 6a 64 4b 94 f5 98 7c d1 f4 92 5c 5c 3e cf 9c 3f 73 71 58 5f af 8b 79 5b ee 96 b6 47 eb f1 ea d1 ce b6 e3 75 3b e6 b9 95 8d c7 ce 3 39 c9 af c6 33 93 7b 66 37 cf ab bf f9 c9 2f 8 80 0 0 10 0 0 2 0 40 0 0 8 0 0 1 0 20 0 0 4 0 80 0 0 10 0 0 2 0 40 0 0 8 0 0 1 0 20 0 0 8c 37 db 68 3 20 fb ed 96 65 0 0 0 0 49 45 4e 44 ae 42 60 82 ffffffff 

问题原因与修正代码

问题点

  1. 未以二进制模式打开文件:PNG是二进制文件,文本模式会自动转换换行符(如将0x0A转为0x0D0A),导致读取数据失真。
  2. 有符号整数的符号扩展:用int存储单字节数据时,0xFF会被扩展为0xFFFFFFFF(因为int是有符号类型),输出时显示为ffffffff。
  3. 循环多读字节:文件大小为size,有效索引范围是0到size-1,target <= size会导致多读一个无效字节。
  4. 低效的文件读取方式:循环中每次seekg+peek的方式效率低,且容易出错。

修正后的代码

#include <iostream>
#include <fstream>
#include <iomanip>

int main()
{
    std::ofstream newImage("gradient-test.txt");
    // 以二进制模式打开输入文件,仅读
    std::ifstream Image("rainbow-gradient-test.png", std::ios::binary);

    // 检查文件是否成功打开
    if (!Image.is_open() || !newImage.is_open()) {
        std::cerr << "文件打开失败" << std::endl;
        return 1;
    }

    // 获取文件大小并重置读取位置
    Image.seekg(0, std::ios::end);
    std::streampos fileSize = Image.tellg();
    Image.seekg(0, std::ios::beg);

    unsigned char byte;
    // 逐字节读取文件
    while (Image.read(reinterpret_cast<char*>(&byte), 1)) {
        // 配置输出格式:两位十六进制、补前导0、大写字母
        newImage << std::hex << std::uppercase 
                 << std::setw(2) << std::setfill('0') 
                 << static_cast<int>(byte) << " ";
    }

    // 关闭文件
    Image.close();
    newImage.close();
    return 0;
}

修正说明

  • 用std::ifstream配合std::ios::binary以二进制只读模式打开PNG文件,避免文本模式的格式转换。
  • 使用unsigned char存储单字节,彻底解决符号扩展问题。
  • 用read()方法逐字节读取,自动处理文件结束,比循环seek更高效可靠。
  • 通过std::setw(2)和std::setfill('0')保证每个字节输出两位十六进制(如0x0A输出为0A),std::uppercase让十六进制字母大写(可替换为std::nouppercase改为小写)。
  • 添加文件打开失败的判断,提升程序健壮性。

内容的提问来源于stack exchange,提问作者caiamari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 06:24:51