基本上我需要将存档中的文件加载到内存中,但由于用户能够修改存档的内容,因此文件偏移量很可能会发生变化。
所以我需要创建一个函数,在十六进制模式的帮助下搜索存档中的文件,返回文件偏移量,将文件加载到内存中并返回文件地址。
要将文件加载到内存中并返回我当前使用的地址:
DWORD LoadBinary(char* filePath)
{
FILE *file = fopen(filePath, "rb");
long fileStart = ftell(file);
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, fileStart, 0);
BYTE *fileBuffer = new BYTE[fileSize];
fread(fileBuffer, fileSize, 1, file);
LPVOID newmem = VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(newmem, fileBuffer, fileSize);
delete[]fileBuffer;
fclose(file);
return (DWORD)newmem;
}
存档既不加密也不压缩,但它很大(大约1 GB),如果可能的话我不想将整个文件加载到内存中。
我知道我在档案中寻找的文件的大小,所以我不需要该函数来找到另一种模式的文件末尾。
文件模式:“\ x30 \ x00 \ x00 \ x00 \ xA0 \ x10 \ x04 \ x00”
文件长度:4096字节
我如何实现这一点以及需要哪些功能?
解决方案
大型文件的代码可能很慢,但这对我有用,因为我正在寻找的文件位于存档的开头。
FILE *file = fopen("C:/data.bin", "rb");
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
rewind(file);
BYTE *buffer = new BYTE[4];
int b = 0; //bytes read
long offset = 0;
for (int i = 0; i < fileSize; i++)
{
int input = fgetc(file);
*(int *)((DWORD)buffer + b) = input;
if (b == 3)
{
b = 0;
}
else {
b = b + 1;
}
if (buffer[0] == 0xDE & buffer[1] == 0xAD & buffer[2] == 0xBE & buffer[3] == 0xEF)
{
offset = (ftell(file) - 4);
printf("Match @ 0x%08X", offset);
break;
}
}
fclose(file);
答案 0 :(得分:1)
原则在this answer中说明:你需要一个有限状态机(FSM),它将文件字节逐个作为输入,并根据FSM状态将当前输入与模式中的字节进行比较,这是一个模式中的索引。
这是最简单但却天真的解决方案模板:
FILE *file = fopen(path, "rb");
size_t state = 0;
for (int input_result; (input_result = fgetc(file)) != EOF;) {
char input = (char)input_result;
if (input == pattern[state]) {
++state;
} else {
state = 0;
}
if (pattern_index == pattern_size) {
// Pattern is found at (ftell(file) - pattern_size).
break;
}
}
fclose(file);
state
变量保持模式中的位置,它是FSM的状态。
虽然这个解决方案满足了您的需求,但它并不是最佳选择,因为从文件中读取一个字节几乎与读取更大的块(例如512字节甚至更多)相同。您可以通过两个步骤自行改进:
fread()
。请注意,模式位置的计算(在找到之后)变得有点复杂,因为ftell()
不再匹配input
位置。