[英]Reading certain part of a .bin file (eg. from 11th 23rd): hex into int, char string. C
我想阅读例如。 十六进制.bin文件中第11至23号之间的数字,如下所示: https : //imgur.com/b4RzPjw ,将某些部分打印为Intiger或将其他部分打印为名称(字符串) 。 (最好不使用任何[ ]
,仅对指针进行操作)
我的示例.bin文件包含:前4个十六进制数字(蓝色突出显示)是名称的长度,然后2个数字是ASCII中的名称。 接下来的4个数字(蓝色下划线)是姓氏的长度(红色下划线),最后一个是索引。
我的尝试:
在将整个.bin文件加载到缓冲区后,完全像这里显示的那样: http : //www.cplusplus.com/reference/cstdio/fread/ ,我很痛苦地尝试了许多方法来将该缓冲区的一部分分配给变量(或结构),然后然后,使用格式将其打印出来,只是看看分配了什么。
char *name_length = malloc(4);
char *pEnd;
for(*buffer=0; *buffer<4; *buffer++) {
sscanf(buffer, "%s", name_length);
long int i = strtol (buffer, &pEnd, 16);
printf("%x", i);
}
上面的(错误的)代码显示0000(我想它是从根部完全烂掉的,尽管我不知道为什么); 如果有一种优雅的方法可以将缓冲零件加载到结构中,则声明如下:
struct student_t
{
char name[20];
char surname[40];
int index;
};
我能得到的“最近”结果是另一个代码,输出为“ 2000”。 从我的.bin文件中:“ 02 00 00 46 2E
”,表示“ 2
0 0 0 / length / F.
/ string /”
for(int i=0; i<4; i++)
printf("%d", buffer[i]); //it's supposed to print first 4 hex digits...
for(int j=5; j<7; j++)
printf("%s", &buffer[j]); //it's supposed to print from 5th to 7th...
非常感谢您提供的所有帮助和指导。
sscanf()
不是用于处理此类二进制数据的正确工具。
从代码的最后一部分开始,您将获得更好的结果,您可以在其中直接索引缓冲区中的每个字符,然后逐个字符地对其进行处理。
请注意,这是在假设buffer是指向字符而不是字符数组的指针的情况下编写的。
您需要做的是读取四个字符以获取长度:
struct student_t result;
int length = 0;
int i;
// Progress backwards down data since it's stored "little endian"
for (i = 3; i >= 0; i--)
{
length = (length << 8) + (buffer[i] & 255);
}
我们只消耗了四个字节,向前移动缓冲区指针以跳过它们:
buffer += 4;
我们有长度,并且缓冲区指针现在指向名称的第一个字符。 阅读那么多字符并保存它们:
for (i = 0; i < length; i++)
{
result.name[i] = *buffer++;
}
// Add a NUL byte to terminate the string.
result.name[i] = '\0';
这将读取名称,然后将其移动到指向下一个长度值的第一个字节的缓冲区指针。 然后,您要做的只是将长度重置为零,然后重复上述操作以读入姓氏。
考虑到我将精确的二进制数据保存在名为data.bin的文件中,下面是一个示例:
code.c :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#define FILE_NAME "data.bin"
typedef struct Record_ {
uint32_t nameLen, surnameLen;
char *name, *surname;
} Record;
void printRecord(Record record) {
printf("\nPrinting record:\n Name length: %u\n Name: [", record.nameLen);
if ((record.nameLen != 0) && (record.name != NULL)) {
char *pc;
for (pc = record.name; pc < record.name + record.nameLen; pc++) {
printf("%c", *pc);
}
}
printf("]\n Surname length: %u\n Surname: [", record.surnameLen);
if ((record.surnameLen != 0) && (record.surname != NULL)) {
char *pc;
for (pc = record.surname; pc < record.surname + record.surnameLen; pc++) {
printf("%c", *pc);
}
}
printf("]\n");
}
void clearRecord(Record *pRecord) {
free(pRecord->name);
free(pRecord->surname);
memset(pRecord, 0, sizeof(Record));
}
int readRecord(FILE *pFile, Record *pRecord) {
size_t readBytes = fread(&pRecord->nameLen, sizeof(pRecord->nameLen), 1, pFile);
if (pRecord->nameLen != 0) {
pRecord->name = malloc(pRecord->nameLen);
readBytes= fread(pRecord->name, 1, pRecord->nameLen, pFile);
}
readBytes = fread(&pRecord->surnameLen, sizeof(pRecord->surnameLen), 1, pFile);
if (pRecord->surnameLen != 0) {
pRecord->surname = malloc(pRecord->surnameLen);
readBytes = fread(pRecord->surname, 1, pRecord->surnameLen, pFile);
}
return 0;
}
int main() {
FILE *fp = fopen(FILE_NAME, "r+b");
if (fp == NULL)
{
printf("Error opening file: %d\n", errno);
return 1;
}
Record record = {0, 0, NULL, NULL};
printRecord(record);
int ret = readRecord(fp, &record);
if (ret)
{
printf("readRecord returned %d\n", ret);
fclose(fp);
return 2;
}
printRecord(record);
clearRecord(&record);
fclose(fp);
return 0;
}
注意事项 :
加载整个.bin文件以完全像这里介绍的那样缓冲
通常,这不是一个好主意。 只阅读所需的内容。 假设您要从数百个MiB大的文件中读取10个字节。 那将完全浪费资源,有时甚至会导致崩溃
似乎您在这里有一个简单的协议:
uint32_t
char *
,因为它的长度是在编译时不知道(你可以有一个像数组: char[SOME_MAX_NAME_LENGTH]
您肯定知道,在之前的场永远不会有大于SOME_MAX_NAME_LENGTH
的值,但我更喜欢这种方法)
这映射在Record
结构上(是的,成员顺序并不重要,只有初始化顺序重要)。 事情可能会更进一步,因为姓氏的数据是name的重复,所以可能有一个内部结构包含name数据,而Record
只能包含一个数组,该数组包含该结构的2个元素。
但是即使这样事情会更简单(而且函数中的代码也会更短-没有重复),我也没有这样做,因为它可能不太明显
printRecord
-显示Record
的数据在一个用户友好的方式(你可以在这里的时候注意到指针逻辑printf
荷兰国际集团在个别字符)
clearRecord
释放char *
成员占用的内存,并将所有内容初始化为0
readRecord
从文件读取数据并填充记录
fread
) sscanf
(函数族)不应该用于二进制数据(字符串除外) )) 输出 :
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q052085090]> gcc code.c -o code.exe && ./code.exe Printing record: Name length: 0 Name: [] Surname length: 0 Surname: [] Printing record: Name length: 2 Name: [F.] Surname length: 13 Surname: [MurrayAbraham]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.