使用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
相关产品推荐
相关产品推荐

