由check50 v3.1.2生成的cs50 / problems / 2020 / x / recover的结果
:) restore.c存在。
:) restore.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);
}
答案 0 :(得分:1)
您的代码有一个顺序错乱的块,导致您创建空文件。在您的代码中,您具有以下内容:
sprintf(FILENAME, "%03i.jpg", counter);
outptr = fopen(FILENAME, "a");
if(outptr != NULL)
{
fclose(outptr);
counter++;
}
使用sprintf()
创建新文件名,然后使用fopen()
打开文件的位置。如果打开成功,则立即用fclose()
关闭关闭文件,并以counter
递增,然后再将任何内容写入文件。不是你想要的。
相反,您想检查当前是否打开了输出文件,如果要打开,则要关闭当前文件,然后打开下一个要写入的输出文件。 (建议使用 mode "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个字符,而将其设置为1个字符。
您可以简单地使用#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()
,您的程序现在可以正常地从card.raw
恢复所有50个jpg文件。
如果您还有其他问题,请告诉我。