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

使用ifstream无法正确获取二进制文件大小的问题求助

问题分析与解决方案

核心问题

  1. 临时文件读取时机错误:在写入temp.bin前就打开了读取流TempFileInput,此时文件内容未完全写入磁盘,读取到的是不完整的旧数据。
  2. 文件复制逻辑存在缺陷:copy_file_data中的循环判断和读取逻辑可能导致字节丢失或读取异常。
  3. 逐字节计算文件大小低效且易出错:通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:24:57