用 C 语言编写一个程序,从存储卡的原始数据中恢复“丢失”的 JPG。我对我的整体代码和逻辑非常有信心,如果我错了,请纠正我,但我在运行时遇到分段错误。
我假设问题出在我的缓冲区数组中。我的目标是制作一个长度为512的int8_t(一个字节)类型的缓冲区数组,然后一次又一次地从存储卡中重复读取一个块到其中,在写入新块时删除前一个块。我想也许不是替换旧块,而是添加到旧块上并超过我的 512 数组。这是我的代码,有什么想法吗?
我也尝试过创建另一个缓冲区作为指针,并向其分配 512 字节的数据,但也没有成功。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 2)
{
printf("Usage: ./recover <filename>\n");
return 1;
}
// Remember file name and open, checking if it opened correctly
char *file_name = argv[1];
FILE *input = fopen(file_name, "r");
if (input == NULL)
{
printf("file <%s> could not be opened\n", file_name);
return 1;
}
// initialize buffer and other variables/types
typedef uint8_t BYTE;
int BLOCK_SIZE = 512;
BYTE buffer[512];
int JPEG_COUNTER = 0;
FILE *img = NULL;
// check if at end of memory card
while (fread(&buffer, 1, BLOCK_SIZE, input) == BLOCK_SIZE)
{ // check if a new JPG has started
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0)
{ //check if the first JPG on card, or start of sequential ones, initialize and write into new file from buffer
if (JPEG_COUNTER < 1)
{
fread(&buffer, 1, BLOCK_SIZE, input);
char *file_name = malloc(17 * sizeof(char));
if (file_name == NULL)
{
return 1;
}
sprintf(file_name, "%.3i.jpg", JPEG_COUNTER);
img = fopen(file_name, "w");
fwrite(&buffer, 1, BLOCK_SIZE, img);
JPEG_COUNTER++;
}
else
{
fclose(img);
fread(&buffer, 1, BLOCK_SIZE, input);
sprintf(file_name, "%.3i.jpg", JPEG_COUNTER);
img = fopen(file_name, "w");
fwrite(&buffer, 1, BLOCK_SIZE, img);
JPEG_COUNTER++;
}
}
// continue writing onto unfinished JPG
else
{
fread(&buffer, 1, BLOCK_SIZE, input);
fwrite(&buffer, 1, BLOCK_SIZE, img);
}
}
free(file_name);
return 0;
}
我尝试了你的代码,并遇到了一系列挑战,因为它涉及尝试识别和问题以使程序更紧密地按预期工作。
第一个问题是确定读取文件的第一个块是“jpg”文件。添加一些“printf”语句可以在终端上提供列出的输出,也可以通过调试器查看。
while (fread(&buffer, 1, BLOCK_SIZE, input) == BLOCK_SIZE)
{ // check if a new JPG has started
printf("Here is what is in the start of the buffer: %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
printf("buffer[3] & 0xf0 results in a value of %d\n", (buffer[3] & 0xf0));
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0)
除了这些附加的“printf”语句之外,“else”块中还添加了另一个“printf”语句,据称该语句将后续数据块打印到输出文件。
else
{
printf("Continue writing blocks after the first block\n");
fread(&buffer, 1, BLOCK_SIZE, input);
fwrite(&buffer, 1, BLOCK_SIZE, img);
}
有了这些额外的信息,立即显示的是,尽管第四个字节是用于测试的“jpg”文件中的实际值,但第一个读取数据块的前四个字节不满足程序的测试条件。
craig@Vera:~/C_Programs/Console/Recover/bin/Release$ ./Recover cat.jpg
Here is what is in the start of the buffer: ff d8 ff e0
buffer[3] & 0xf0 results in a value of 224
Continue writing blocks after the first block
Segmentation fault (core dumped)
对第四个字节执行“and”操作没有得到预期的零值,因此不会打开输出文件,随后,当尝试写入该文件时,会发生未定义的行为“write”很可能被推送到 NULL 指针。
因此,重构该测试以仅检查前三个字节确实最初定义了输出文件指针(“img”)并开始将数据写入输出文件。然而,当读写周期完成时,程序使用了“free”函数,这不是正确的操作,导致另一个程序转储。
printf("Exited the while loop\n");
free(file_name);
return 0;
Continue writing blocks after the first block
Here is what is in the start of the buffer: 5 83 8f ca
buffer[3] & 0xf0 results in a value of 192
Continue writing blocks after the first block
Exited the while loop
munmap_chunk(): invalid pointer
Aborted (core dumped)
“fclose”语句将取代“free”函数。
printf("Exited the while loop\n");
fclose(img);
return 0;
通过这些初始的重构,程序确实运行完成并创建了一个文件。但是,当尝试使用图像查看实用程序查看创建的文件时,该文件将无法正确打开。
Could not load image '000.jpg'
此外,当查看创建的文件的大小属性时,它大约是正在测试的原始输入文件大小的一半。
File size of cat.jpg: 136.6 kb
File size of 000.jpg 68.1 kb
这是因为“while”循环中的每个文件写入实际上都会读取输入文件两次。
完成所有这些后,我退后一步,查看“while”循环中“读取”和“写入”应该发生的位置。以下是代码的重构版本,用于解决许多问题,至少提供一个功能性的文件复制程序。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define BLOCK_SIZE 512
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 2)
{
printf("Usage: ./recover <filename>\n");
return 1;
}
// Remember file name and open, checking if it opened correctly
char *file_name = argv[1];
FILE *input = fopen(file_name, "r");
int x; /* Used this to handle any last block size that is not 512 bytes */
if (input == NULL)
{
printf("file <%s> could not be opened\n", file_name);
return 1;
}
// initialize buffer and other variables/types
typedef uint8_t BYTE;
BYTE buffer[BLOCK_SIZE];
int jpeg_counter = 0;
FILE *img = NULL;
// check if at end of memory card
while (1) /* Simplify while loop logic */
{
x = fread(buffer, 1, BLOCK_SIZE, input); /* Check if at the end of the memory card */
printf("Block size read: %d\n", x); /* Added for debug information */
if (x != BLOCK_SIZE) /* Final partial block writing */
{
fwrite(buffer, 1, x, img);
break; /* Exit the while loop here */
}
// Check if a new JPG has started
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && buffer[3] == 0xe0) /* ff d8 ff e0 were found as the first bytes of a jpeg file */
{
//check if the first JPG on card, or start of sequential ones, initialize and write into new file from buffer
if (jpeg_counter < 1)
{
printf("jpeg_counter: %d\n", jpeg_counter); /* Added for debug information */
//fread(buffer, 1, BLOCK_SIZE, input);
char *file_name = malloc(17 * sizeof(char));
if (file_name == NULL)
{
return 1;
}
sprintf(file_name, "%.3i.jpg", jpeg_counter);
img = fopen(file_name, "w");
fwrite(buffer, 1, BLOCK_SIZE, img);
jpeg_counter++;
}
else
{
printf("jpeg_counter: %d\n", jpeg_counter); /* Added for debug information */
fclose(img);
//fread(buffer, 1, BLOCK_SIZE, input);
sprintf(file_name, "%.3i.jpg", jpeg_counter);
img = fopen(file_name, "w");
fwrite(buffer, 1, BLOCK_SIZE, img);
jpeg_counter++;
}
}
// Continue writing onto unfinished JPG
else
{
printf("Reading and writing file\n"); /* Added for debug information */
fwrite(buffer, 1, BLOCK_SIZE, img);
}
}
fclose(input); /* Close the files */
fclose(img);
return 0;
}
我很抱歉将整个程序包括在内,因为重构涵盖了整个程序。以下是重点。
结果是执行程序生成了用于测试的“jpg”文件的副本。文件大小匹配,并且可以使用图像查看器实用程序打开和查看新文件。
照原样,该程序要么复制实际的“jpg”文件,要么在读取其他类型的文件时出现分段错误。因此,仍有改进的空间。希望这能提供一些关于什么有效、什么无效的想法。由此得出的结论可能是深入研究“C”教程文献,因为它涉及文件处理(打开、读取、写入等)、“while”循环处理以及图像文件的字节序列,例如“ jpg”文件。