使用ifstream无法正确获取二进制文件大小的问题求助
问题分析与解决方案
核心问题
- 临时文件读取时机错误:在写入
temp.bin前就打开了读取流TempFileInput,此时文件内容未完全写入磁盘,读取到的是不完整的旧数据。 - 文件复制逻辑存在缺陷:
copy_file_data中的循环判断和读取逻辑可能导致字节丢失或读取异常。 - 逐字节计算文件大小低效且易出错:通过
get()循环计数的方式不仅效率低,还可能因流状态或二进制数据的特殊值(如DOS下的EOF标记0x1A)导致计数错误。
修复步骤与代码修改
1. 修正临时文件打开时机
在main函数中,将TempFileInput.open移到写入完成并关闭TempFileOutput之后,确保所有数据写入磁盘:
// 移除原代码中提前打开TempFileInput的语句 // TempFileInput.open("temp.bin", std::ios::in | std::ios::binary); // ... 写入temp.bin的代码执行完成后 ... TempFileOutput.close(); // 关闭写入流,强制数据落盘 TempFileInput.open("temp.bin", std::ios::in | std::ios::binary); TempFileInput.unsetf(std::ios::skipws);
2. 重写高效的文件大小计算函数
替换get_file_size为基于流指针的标准实现,避免逐字节读取的问题:
std::streamsize get_file_size(std::ifstream &File) { File.clear(); std::streampos original_pos = File.tellg(); // 保存当前读取位置 File.seekg(0, std::ios::end); std::streamsize size = File.tellg(); File.seekg(original_pos); // 恢复原读取位置 std::cout << "get_file_size: " << std::hex << size << std::endl; return size; }
3. 修复文件复制函数逻辑
简化copy_file_data,用更可靠的方式复制二进制文件:
bool copy_file_data(std::ifstream *FileIn, std::ofstream *FileOut) { if (!FileIn->is_open() || !FileOut->is_open()) { return false; } // 直接用流的read/write批量复制,高效且避免逐字节的异常 FileIn->seekg(0, std::ios::beg); std::streamsize size = get_file_size(*FileIn); char* buffer = new char[size]; FileIn->read(buffer, size); FileOut->write(buffer, size); delete[] buffer; std::cout << "SizeInsideCopy: " << std::hex << size << std::endl; return true; }
如果需要保留逐字节方式,使用正确的循环判断:
bool copy_file_data(std::ifstream *FileIn, std::ofstream *FileOut) { char c; std::streamsize size = 0; if (!FileIn->is_open() || !FileOut->is_open()) { return false; } FileIn->seekg(0, std::ios::beg); while (FileIn->get(c)) // 直接通过get的返回值判断是否读取有效字节 { size++; FileOut->put(c); } std::cout << "SizeInsideCopy: " << std::hex << size << std::endl; return true; }
4. 完整修改后的main函数关键片段
// ... 初始化部分 ... FileInput.open(BinaryFilePath.c_str(), std::ios::in | std::ios::binary); TempFileOutput.open("temp.bin", std::ios::out | std::ios::binary); FileInput.unsetf(std::ios::skipws); TempFileOutput.unsetf(std::ios::skipws); if (!FileInput.is_open() || !TempFileOutput.is_open()) { std::cout << "Cannot open files" << std::endl; return -2; } // 写入8字节头部 char s8FirmwareCrc[4] = { 0 }; char s8FirmwareSize[4] = { 0 }; TempFileOutput.write(s8FirmwareCrc, 4); TempFileOutput.write(s8FirmwareSize, 4); if (!copy_file_data(&FileInput, &TempFileOutput)) { std::cout << "Error reading files" << std::endl; FileInput.close(); TempFileOutput.close(); return -3; } // 关闭写入流,确保数据完全写入磁盘 TempFileOutput.close(); // 打开临时文件读取流 TempFileInput.open("temp.bin", std::ios::in | std::ios::binary); TempFileInput.unsetf(std::ios::skipws); char *buff = NULL; get_file_size(FileInput); read_whole_file(TempFileInput, buff, 4); // 关闭所有流 FileInput.close(); TempFileInput.close();
验证说明
修改后,temp.bin的读取操作会在所有写入完成并落盘后执行,文件大小计算使用标准的流指针方法,避免了逐字节读取的异常,最终读取的大小会与HxD工具验证的3d6c7一致。
内容的提问来源于stack exchange,提问作者artik15
相关产品推荐
相关产品推荐

