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

使用堆内存读取文件后缓冲区无有效数据的问题求助

问题分析与解决:fread写入堆内存后数据无效

问题根源

你的代码核心问题出在参数传递错误:

  • 在main中,你把buffer指针的地址((char**)&buffer)传给了File::Read的void* buf参数。
  • 而File::Read里直接把buf传给fread,相当于把文件内容写入了buffer这个指针变量本身的内存空间(而非buffer指向的堆内存),这就导致后续访问buffer指向的堆内存时,里面仍是垃圾数据。
  • 另外,File::Read内部重新计算的fileSize可能和main中File.Tell()获取的filesize不一致,也可能引发数据读取不完整的问题。

解决方案

你不需要在File::Read里重新分配内存,只需要修正参数传递和函数参数的匹配:

方案1:修改File::Read的参数为直接接收数据缓冲区指针

调整Read函数的参数类型,让它直接接收你在main中分配好的堆内存指针:

// 修改File类的Read函数声明
size_t File::Read(char* buf, size_t bufSize) {
    // 用传入的bufSize作为读取上限,避免缓冲区溢出
    ::fseek(fStream, 0, SEEK_END);
    int fileSize = ::ftell(fStream);
    ::fseek(fStream, 0, SEEK_SET);
    
    // 取文件大小和缓冲区大小的最小值,防止溢出
    size_t readSize = std::min(static_cast<size_t>(fileSize), bufSize);
    ::fread(buf, 1, readSize, fStream);
    
    return readSize;
}

// main中调用方式修改为
int main(...) {
  MyFile File;
  File.Open(...);
  int filesize = File.Tell();
  char* buffer = new char[filesize]; 
  // 直接传buffer指针,同时传入缓冲区大小
  File.Read(buffer, filesize);

  // 现在buffer里就是有效数据了

  File.Close();
  delete [] buffer;
}

方案2:如果要保留void*参数(不推荐,类型不安全)

如果一定要用void*作为参数,那么main中直接传递buffer即可,不需要传二级指针:

size_t File::Read(void* buf, size_t bufSize) {
    ::fseek(fStream, 0, SEEK_END);
    int fileSize = ::ftell(fStream);
    ::fseek(fStream, 0, SEEK_SET);
    
    size_t readSize = std::min(static_cast<size_t>(fileSize), bufSize);
    ::fread(buf, 1, readSize, fStream);
    
    return readSize;
}

// main中调用
File.Read(buffer, filesize);

额外注意事项

  • 永远要考虑缓冲区溢出问题,不要直接用文件大小作为读取长度,要和缓冲区大小做比较。
  • ftell返回的是long类型,强转成size_t时要注意溢出风险。
  • 如果你的File::Tell()已经能正确获取文件大小,File::Read里可以直接使用传入的bufSize,不需要重复计算文件大小,减少IO操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:10:43