c - CS50 恢复问题 - 恢复的图像不匹配
问题描述
由 check50 v3.1.2 生成的 cs50/problems/2020/x/recover 的结果 :) recover.c 存在。
:) recover.c 编译。
:) 处理缺少取证图像
:( 正确恢复 000.jpg 恢复图像不匹配
:( 正确恢复中间图像 恢复图像不匹配
:( 恢复 049.jpg 正确恢复图像不匹配
我不知道为什么我会面临这个问题。请帮助我,这可能是因为我不清楚文件基础或其他内容。
#include <stdio.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
//to check for command-line arguments
if( argc !=2 )
{
printf("Usage: ./recover imagename");
return 1;
}
//file pointer from where to read
FILE *inptr = fopen(argv[1], "r");
if( inptr == NULL)
{
fprintf(stderr, "File couldn't open");
return 1;
}
BYTE buffer[512]; //buffer for storing input data from file
char FILENAME[8]; //output file name storage
int counter=0; //to handle naming of file
FILE *outptr = NULL; //file pointer where to write
while(fread(buffer, 512, 1, inptr))
{
if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
sprintf(FILENAME, "%03i.jpg", counter);
outptr = fopen(FILENAME, "a");
if(outptr != NULL)
{
fclose(outptr);
counter++;
}
}
if(outptr != NULL)
{
fwrite(buffer, 512, 1, outptr);
}
}
fclose(outptr);
fclose(inptr);
}
解决方案
您的代码有一个块乱序导致您创建空文件。在您的代码中,您具有以下内容:
sprintf(FILENAME, "%03i.jpg", counter);
outptr = fopen(FILENAME, "a");
if(outptr != NULL)
{
fclose(outptr);
counter++;
}
在哪里创建新文件名,sprintf()
然后用fopen()
. 如果打开成功,则在将任何内容写入文件之前立即关闭文件fclose()
并递增。counter
不是你想要的。
相反,您要检查当前是否打开了输出文件,如果是,则要关闭当前文件,然后打开下一个输出文件进行写入。(建议使用模式 "wb"
而不是打开"a"
)。重新排列,您将拥有:
if(outptr != NULL) /* if output file open, close before opening next */
{
fclose(outptr);
counter++;
}
sprintf(FILENAME, "%03d.jpg", counter);
outptr = fopen(FILENAME, "wb"); /* open in write, not append mode */
现在您的文件将保持打开状态,因此您可以将恢复的 jpg 写入文件。
避免硬编码文件名或使用幻数
你的文件名做得很好,但你应该为你的代码中使用的数字声明常量。为什么?当您#define
在代码顶部设置一个常量时,您提供了一个方便的位置来调整任何固定值,而不必为了进行更改而选择所有循环限制和函数调用。此外,在为文件名等声明缓冲区时,不要吝啬缓冲区大小...... 最好有一个 1000 个字符太长的缓冲区,而它的一个字符太短。
您可以简单地使用#define
来定义一个或多个常量或使用全局enum
来实现相同的目的。在这里你可以这样做:
#define BLKSZ 512 /* if you need a constant, #define one (or more) */
#define MAXFN 1024 /* (don't skimp on buffer size) */
...
然后你的用途是:
...
BYTE buffer[BLKSZ]; /* don't use MagicNumbers, use a constant */
char FILENAME[MAXFN]; /* ditto */
...
while (fread(buffer, BLKSZ, 1, inptr))
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 &&
buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if(outptr != NULL) /* if output file open, close before opening next */
{
fclose(outptr);
counter++;
}
sprintf(FILENAME, "%03d.jpg", counter);
outptr = fopen(FILENAME, "wb"); /* open in write, not append mode */
}
if(outptr != NULL)
{
fwrite(buffer, BLKSZ, 1, outptr);
}
}
(注意:你想通过换行来控制长行,以防止不必要的换行,这会使代码难以阅读。最近 Linux 内核样式指南将推荐的每行字符从 80 个字符提高到 100 个字符 - 虽然,在 StackOverflow 上,您会注意到您的行开始需要滚动条超过 90 个字符)
现在,如果有任何变化,您需要更改两个简单的常量。
通过重新排序fclose()
调用,您的程序现在可以恢复所有 50 个 jpg 文件card.raw
。
如果您还有其他问题,请告诉我。
推荐阅读
- javascript - 如何复制文件夹中的文件进行构建?
- python - numpy.linalg.eig 返回的特征值何时排序?
- python - python - 如何迭代字符串/数组
- raspberry-pi3 - 无法更新 Raspbian
- c++ - Forward Declaration and Accessing member functions in an inherited class
- sleep - 智能手表访问
- css - 在 index.html 的顶部添加了捆绑的 css
- vue.js - 在构建时显示图像并从 Vue 和 Electron 开始的问题
- c - C 中的正则表达式来限制扩展的 ASCII 字符集
- cmake - 我将如何使用 CMake 包含 asio 库?