CS50 recover.c运行生成空白JPEG图像,请求技术帮助
问题分析与修复方案
你的代码存在两个关键问题,导致生成的JPEG全为空白:
1. 仅写入了JPEG的首个数据块
JPEG文件由连续的多个512字节块组成,但你的代码仅在检测到JPEG签名时,写入当前块就立刻关闭文件。后续属于该JPEG的块没有被持续写入,最终每个生成的文件只有512字节,无法被图像查看器识别为完整的JPEG文件。
正确逻辑应为:
- 首次检测到JPEG签名时,打开新文件并写入当前块
- 后续块(直到下一个JPEG签名出现前)持续写入当前打开的文件
- 检测到新JPEG签名时,先关闭当前文件,再打开新文件写入
2. 未使用二进制模式操作文件
在Windows系统中,默认的文本模式("r"/"w")会自动处理换行符,破坏JPEG的二进制数据。必须使用二进制模式("rb"/"wb")打开文件,确保数据读写时不被篡改。
修改后的完整代码
#include <stdio.h> #include <stdlib.h> #include <stdint.h> int main(int argc, char *argv[]) { // 检查命令行参数 if (argc != 2) { printf("ERROR: Invalid command line argument, enter only 1 file.\n"); return 1; } // 以二进制模式打开存储卡文件 FILE *card = fopen(argv[1], "rb"); if (card == NULL) { printf("Error: opening file.\n"); return 2; } // 初始化变量 uint8_t buffer[512]; int counter = 0; FILE *recovered_jpeg = NULL; char filename[9]; // 循环读取存储卡数据 while (fread(buffer, 1, 512, card) == 512) { // 检测JPEG签名 if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // 若已有打开的JPEG文件,先关闭 if (recovered_jpeg != NULL) { fclose(recovered_jpeg); } // 检查文件数量是否超限 if (counter > 999) { printf("Error: file overload.\n"); return 3; } // 生成文件名 sprintf(filename, "%03d.jpeg", counter); counter++; // 以二进制模式打开新JPEG文件 recovered_jpeg = fopen(filename, "wb"); if (recovered_jpeg == NULL) { printf("Error: opening file.\n"); return 4; } } // 若当前有打开的JPEG文件,写入当前块 if (recovered_jpeg != NULL) { fwrite(buffer, 512, 1, recovered_jpeg); } } // 循环结束后关闭最后一个JPEG文件 if (recovered_jpeg != NULL) { fclose(recovered_jpeg); } fclose(card); return 0; }
修改说明
- 将
fopen模式改为"rb"/"wb",确保二进制数据正确读写 - 调整写入逻辑:仅在检测到新JPEG时切换文件,后续块持续写入当前文件
- 循环结束后关闭最后一个JPEG文件,避免资源泄漏
- 将原有的
while(argc !=2)改为if,因为这是一次性参数检查,无需循环
内容的提问来源于stack exchange,提问作者Tyler
相关产品推荐
相关产品推荐

