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

使用ifstream.read读取Exif数据到vector失败,buffer为空求助

问题分析与修复方案

核心问题1:vector始终为空

你使用buffer.reserve(length)仅预留了内存空间,但vector的size()仍为0。std::ifstream::read()会写入预留的内存,但不会自动更新vector的大小。必须改用buffer.resize(length),这样vector会分配内存并将size()设置为length,读取后就能正确获取数据长度。

核心问题2:Exif标记定位错误

JPEG的Exif数据位于APP1标记中,该标记的完整标识是0xFFE1(以0xFF开头的JPEG段标记),而非单独的0xE1。直接跳到固定偏移0xE1完全错误,需要遍历文件找到0xFF后跟0xE1的位置:

// 寻找FF E1标记
uint8_t byte1, byte2;
while (infile.read(reinterpret_cast<char*>(&byte1), 1)) {
    if (byte1 == 0xFF) {
        if (infile.read(reinterpret_cast<char*>(&byte2), 1) && byte2 == 0xE1) {
            break; // 找到APP1标记
        }
    }
}
if (!infile) {
    std::cout << "Error: No Exif APP1 tag found\n";
    exit(1);
}

核心问题3:字节序不匹配

Exif的长度字段采用大端字节序,而多数系统是小端字节序。直接读取unsigned short会导致数值错误,需要手动转换:

unsigned char len_bytes[2];
infile.read(reinterpret_cast<char*>(len_bytes), 2);
unsigned short length = (static_cast<unsigned short>(len_bytes[0]) << 8) | len_bytes[1];
// APP1长度包含自身2字节,所以实际Exif数据长度是length - 2
unsigned short exif_data_len = length - 2;

核心问题4:读取位置错误

找到0xFFE1标记后,读取2字节长度,接下来的位置就是Exif数据的起始点,无需再跳回0xE1位置。

核心问题5:遍历逻辑错误

for (int i : buffer)中的i是vector的元素值而非索引,使用buffer[i]会导致越界。同时0x9003是两字节的标记,不能与单字节元素直接比较:

// 正确遍历示例
for (size_t i = 0; i < buffer.size(); ++i) {
    if (buffer[i] == 0xE1) {
        std::cout << std::hex << static_cast<int>(buffer[i]) << " ";
    }
    // 检查连续两字节是否为0x9003
    if (i + 1 < buffer.size()) {
        uint16_t two_bytes = (static_cast<uint16_t>(buffer[i]) << 8) | buffer[i+1];
        if (two_bytes == 0x9003) {
            std::cout << std::hex << two_bytes << " ";
        }
    }
}

修复后的完整代码示例

#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <cstdlib>

void File_iterate(const std::string* Filename) {
    std::ifstream infile(*Filename, std::ios::binary);
    if (!infile) {
        std::cout << "Error: file unavailable\n";
        exit(1);
    }

    // 寻找JPEG APP1标记(FF E1)
    uint8_t byte1, byte2;
    while (infile.read(reinterpret_cast<char*>(&byte1), 1)) {
        if (byte1 == 0xFF) {
            if (infile.read(reinterpret_cast<char*>(&byte2), 1) && byte2 == 0xE1) {
                break;
            }
        }
    }
    if (!infile) {
        std::cout << "Error: No Exif APP1 tag found\n";
        exit(1);
    }

    // 读取并转换大端字节序的长度
    unsigned char len_bytes[2];
    infile.read(reinterpret_cast<char*>(len_bytes), 2);
    unsigned short length = (static_cast<unsigned short>(len_bytes[0]) << 8) | len_bytes[1];
    unsigned short exif_data_len = length - 2; // 减去长度字段自身的2字节

    // 获取文件大小用于验证
    infile.seekg(0, std::ios::end);
    std::cout << "APP1 segment length:  " << length << " bytes.\n";
    std::cout << "Actual Exif data length: " << exif_data_len << " bytes.\n";
    std::cout << "Size of file:     " << infile.tellg() << " bytes\n";

    // 回到Exif数据起始位置
    infile.seekg(-static_cast<std::streamoff>(exif_data_len + 2), std::ios::end);
    std::vector<uint8_t> buffer(exif_data_len); // 直接初始化size为数据长度
    infile.read(reinterpret_cast<char*>(buffer.data()), exif_data_len);

    std::cout << "Length of buffer: " << buffer.size() << " bytes\n";

    // 遍历检查标记
    for (size_t i = 0; i < buffer.size(); ++i) {
        if (buffer[i] == 0xE1) {
            std::cout << std::hex << static_cast<int>(buffer[i]) << " ";
        }
        if (i + 1 < buffer.size()) {
            uint16_t two_bytes = (static_cast<uint16_t>(buffer[i]) << 8) | buffer[i+1];
            if (two_bytes == 0x9003) {
                std::cout << std::hex << two_bytes << " ";
            }
        }
    }
    std::cout << std::dec << "\n";

    infile.close();
}

int main() {
    std::string filename = "test.jpg";
    File_iterate(&filename);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:37:49