C++代码复制Windows系统文件后大小异常问题咨询
复制System32文件异常的问题分析与修复
现象
用你提供的C++代码复制C:\Windows\System32\calc.exe到桌面生成aa.exe,文件大小和源文件不一致但仍可正常运行;用CMD的copy命令复制时,目标文件与源文件大小完全匹配。
问题原因
1. 多余的文件指针定位操作
代码中每次循环都调用fseek(fp, unReadLen, SEEK_SET)完全没必要——fread执行成功后,文件指针会自动向后移动对应读取字节数,手动定位属于画蛇添足。若某次读取出现异常(如count计算偏差),会直接导致重复读取或跳过部分内容,最终造成目标文件大小异常。
2. 二进制数据的字符串处理错误
代码里用szFileData.append(databuf)将二进制数据追加到字符串时,append默认会把databuf当作C风格字符串,遇到\0(空字符)就停止追加。可执行文件作为二进制文件,内部大量存在\0,这会导致szFileData内容不完整;不过这步操作不影响文件写入(写入依赖fwrite按实际读取的count字节执行),但属于错误的处理逻辑。
3. 未处理目标文件打开失败场景
若桌面路径不存在或无写入权限,fp2会变为NULL,后续fwrite操作会直接导致程序崩溃,原代码未做任何错误处理。
4. 可能的系统重定向差异
如果你的C++程序是32位版本,在64位Windows系统中,访问C:\Windows\System32会被系统自动重定向到C:\Windows\SysWOW64目录,读取的是32位版calc.exe;而64位CMD复制的是System32目录下的64位版calc.exe,两个源文件本身大小就不同,自然复制后的文件大小存在差异。
修复后的代码
#include <cstdio> #include <cstring> #include <string> #define FILE_NAME_MAX_SIZE 512 #define buf_len 1024 // 增大缓冲区,提升复制效率 int main() { std::string szFileData; char file_name[FILE_NAME_MAX_SIZE + 1] = {0}; char databuf[buf_len] = {0}; // 二进制缓冲区无需额外+1,避免混淆 // 打开源文件 FILE* fp = fopen("C:\\Windows\\System32\\calc.exe", "rb"); if (fp == NULL) { printf("源文件打开失败!\n"); return 1; } // 打开目标文件 FILE* fp2 = fopen("C:\\Users\\OS\\Desktop\\aa.exe", "wb"); if (fp2 == NULL) { printf("目标文件打开失败!\n"); fclose(fp); return 1; } size_t count = 0; // 循环读取并写入,依赖fread自动移动文件指针 while ((count = fread(databuf, 1, buf_len, fp)) > 0) { fwrite(databuf, 1, count, fp2); // 追加二进制数据到string,必须指定长度,避免\0截断 szFileData.append(databuf, count); memset(databuf, 0, sizeof(databuf)); } printf("复制完成\n"); // 关闭文件 fclose(fp); fclose(fp2); return 0; }
关键修复点
- 移除多余的
fseek和unReadLen变量,让fread自动管理文件指针,避免定位错误。 - 将缓冲区大小调整为1024,大幅提升复制效率(原5字节缓冲区会导致大量IO操作,效率极低)。
- 增加目标文件打开失败的处理逻辑,避免程序崩溃。
- 使用
szFileData.append(databuf, count)重载方法追加二进制数据,指定字节数,解决\0截断问题。 - 若要读取真正的System32目录下的64位文件,可将程序编译为64位版本,或调用Windows API
Wow64DisableWow64FsRedirection关闭文件系统重定向。
内容的提问来源于stack exchange,提问作者hahaha1144
相关产品推荐
相关产品推荐

