我正在尝试扫描一个文件,查找将连续存储的1MB JPEG。我的方法是创建一个结构,将前4个字节与JPEG签名匹配,如果为true,则将整个512缓冲区写入命名文件,直到找到另一个jpeg签名,然后创建一个新文件。下面的代码创建了2个文件,这两个文件都不可读,因为前几个字节不是jpeg签名的一部分。我出错的任何想法?我尝试了我的if语句的变体,我在那里测试签名但到目前为止没有运气。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
typedef struct
{
BYTE first;
BYTE second;
BYTE third;
BYTE fourth;
}
JPGTEST;
int main(int argc, char* argv[])
{
FILE* inptr = fopen("card.raw", "r");
if (inptr == NULL)
{
printf("Could not open file\n");
return 2;
}
FILE* outptr;
//initialize jpeg count and variable for filename
int count = 0;
char name[8];
//allocate memory
char buffer[512];
JPGTEST myjpg;
int is_open = 0;
while (fread(&buffer, 512, 1, inptr) != 0)
{
//test first 4 bytes to see if jpeg
fread(&myjpg, sizeof(JPGTEST), 1, inptr);
//if match, name and write to file
if (myjpg.first == 0xff && myjpg.second == 0xd8 && myjpg.third == 0xff && (myjpg.fourth == 0xe0 || myjpg.fourth == 0xe1))
{
sprintf(name, "%03d.jpg", count);
if (is_open == 0)
{
outptr = fopen(name, "w");
fwrite(buffer, sizeof(buffer),1,outptr);
is_open = 1;
}
if (is_open == 1)
{
fclose(outptr);
outptr = fopen(name, "w");
fwrite(buffer, sizeof(buffer),1,outptr);
count++;
}
}
else
{
if (is_open == 1)
{
fwrite(buffer, sizeof(buffer),1,outptr);
}
}
}
fclose(inptr);
fclose(outptr);
return 0;
}
答案 0 :(得分:2)
您正在文字模式中打开文件。您需要以二进制模式打开它们:
FILE* inptr = fopen("card.raw", "rb");
outptr = fopen(name, "wb");
除此之外,您正在多次调用fread()
,而且通常无法正确管理文件。
请尝试更多内容:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
#pragma pack(push, 1)
typedef struct
{
BYTE first;
BYTE second;
BYTE third;
BYTE fourth;
}
JPGTEST;
#pragma pack(pop)
int main(int argc, char* argv[])
{
FILE* inptr = fopen("card.raw", "rb");
if (inptr == NULL)
{
printf("Could not open file\n");
return 2;
}
FILE* outptr = NULL;
//initialize jpeg count and variable for filename
int count = 0;
char name[8];
//allocate memory
char buffer[512];
JPGTEST myjpg;
while (fread(buffer, sizeof(buffer), 1, inptr) > 0)
{
//test first 4 bytes to see if jpeg
memcpy(&myjpg, buffer, sizeof(JPGTEST));
//if match, name and write to file
if ((myjpg.first == 0xff) && (myjpg.second == 0xd8) && (myjpg.third == 0xff) && ((myjpg.fourth == 0xe0) || (myjpg.fourth == 0xe1)))
{
if (outptr != NULL)
{
fclose(outptr);
outptr = NULL;
}
++count;
sprintf(name, "%03d.jpg", count);
outptr = fopen(name, "wb");
}
if (outptr != NULL)
fwrite(buffer, sizeof(buffer), 1, outptr);
}
fclose(inptr);
if (outptr != NULL)
fclose(outptr);
return 0;
}
答案 1 :(得分:1)
使用以下内容替换循环内的第二个 fread :
memcpy((void *)&myjpg, (void *) buffer, sizeof(JPGTEST));
在 memcpy 函数的代码中包含string.h头文件。
你所做错的是,在读完第512页后你没有使用它们,而是你再次读取4个字节而不检查先前读取的512字节的前4个字节。
答案 2 :(得分:0)
问题是您在阅读buffer
后没有重置文件位置指示符,为此请使用fseek
。即:
//test first 4 bytes to see if jpeg
fseek (inptr, SEEK_SET, 0);
fread(&myjpg, sizeof(JPGTEST), 1, inptr);
这将为您提供myjpg
中的jpg标题的测试:
sizeof (myjpg): 4
first: ff second: d8 third ff fourth: e0
但是,这也会导致您必须返工的逻辑问题。最好只读取buffer
中的值,如另一个答案所示。
答案 3 :(得分:0)
您可以执行以下操作来简化签名比较:
#include ...
#define JPEG_SIGNATURE 0xFFD8
void
reverse_bytes (void const *data, long unsigned size)
{
char *ptr = (char *)data;
int i = 0;
while (i < size / 2)
{
char temp = ptr[i];
ptr[i] = ptr[size - i - 1];
ptr[size - i - 1] = temp;
i++;
}
}
int
main()
{
FILE *fptr = fopen("path/to/image.jpeg", "rb");
short bytes = 0;
fread(&bytes, sizeof(char), sizeof(bytes), fptr);
reverse_bytes(bytes, sizeof(bytes)); // Refer to [1]
switch (bytes)
{
case JPEG_SIGNATURE:
printf("JPEG image!");
break;
default:
printf("Unknown format!");
break;
}
return 0;
}
这可以通过在 switch 语句中添加更多 case 和更多工作来扩展到许多不同的格式。
这确实不是一个完整或正确的答案,但我希望它对其他人通过这篇文章有所帮助!
注意:为简洁起见,我省略了诸如异常处理之类的内容!
参考: