简体   繁体   English

将二进制文件结构化为数组C

[英]Structures binary file into array C

I need to put structs from a binary file into an array of structs, one struct per key. 我需要将一个二进制文件中的结构放入一个结构数组中,每个键一个结构。

Here is my struct: 这是我的结构:

struct candidate{
    char inscr[10];
    char name[44];
    int year;
    int position;
    char curse[30];
};
typedef struct candidate Candidate;

Here's what I tried to do: 这是我尝试做的事情:

void ordenafile(char fname[13]){
FILE *f = fopen (fname, "rb");
if(f==NULL){
    printf("Error.");
return;
}
fseek(f, 0, SEEK_END);
int  sz = ftell(f);
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
    arr[i]=p;
    i++;
}

Having found the end of the file with fseek() , you need to rewind before reading from it. 使用fseek()找到了文件的末尾,您需要先倒带,然后再读取文件。

This part of the code doesn't do what you want: 这部分代码无法满足您的要求:

Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
    arr[i]=p;
    i++;
}

You have an array of structure pointers, and you allocate one structure, pointed at by p . 您有一个结构指针数组,并分配了一个由p指向的结构。 Your loop then reads a value into the one structure, and copies the pointer into an element of the array of pointers. 然后,循环将一个值读取到一个结构中,并将指针复制到指针数组的一个元素中。 So, all the elements of the array point to the same structure. 因此,数组的所有元素都指向相同的结构。 The variable aux is also unused. 变量aux也未使用。

You need one of two solutions: 您需要以下两种解决方案之一:

Candidate arr[sz/sizeof(Candidate)];
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
    ;

This assumes you are going to be able to use the array in the current function and functions it calls, and don't need to return it to the calling code. 这假定您将能够在当前函数和它调用的函数中使用该数组,而无需将其返回给调用代码。

Alternatively: 或者:

Candidate *arr = malloc(sz);
if (arr == 0)
    return 0;
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
    ;

return arr;

You can return this array from the function. 您可以从函数返回此数组。


Working code 工作代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct candidate
{
    char inscr[10];
    char name[44];
    int year;
    int position;
    char curse[30];
};
typedef struct candidate Candidate;

int write_sample_data(const char *filename);
Candidate *read_sample_data(const char *filename, int *number);
void print_sample_data(int num, Candidate *candidates);

int main(void)
{
    const char filename[] = "practice.data";

    if (write_sample_data(filename) != 0)
        fprintf(stderr, "Failed to write sample data\n");
    else
    {
        int number = 0;
        Candidate *clist = read_sample_data(filename, &number);
        if (number == 0)
            fprintf(stderr, "Failed to read sample data\n");
        else
        {
            print_sample_data(number, clist);
            free(clist);
        }
    }
    return 0;
}

int write_sample_data(const char *filename)
{
    FILE *fp = fopen(filename, "wb");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file %s for writing\n", filename);
        return -1;
    }
    Candidate c;
    for (int i = 0; i < 5; i++)
    {
        char inscr[10];
        char name[40];
        char curse[30];
        sprintf(inscr, "I-%.4d", i);
        sprintf(name, "Name %.4d Surname %.4d", rand() % 1000, rand() % 1000);
        sprintf(curse, "Curse %.2d", rand() % 100);
        // Using null-filling property of strncpy()
        strncpy(c.inscr, inscr, sizeof(c.inscr));
        strncpy(c.name, name, sizeof(c.name));
        strncpy(c.curse, curse, sizeof(c.curse));
        c.year = 2010 + i;
        c.position = 1000 * i + (99 - i);
        if (fwrite(&c, sizeof(Candidate), 1, fp) != 1)
        {
            fclose(fp);
            fprintf(stderr, "Failed to write candidate %d\n", i);
            return -1;
        }
    }
    fclose(fp);
    return 0;
}

Candidate *read_sample_data(const char *filename, int *number)
{
    FILE *fp = fopen(filename, "rb");

    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", filename);
        return 0;
    }
    fseek(fp, 0, SEEK_END);
    size_t sz = ftell(fp);
    rewind(fp);

    Candidate *arr = malloc(sz);
    if (arr == 0)
    {
        fprintf(stderr, "Failed to allocate %zu bytes memory\n", sz);
        return 0;
    }

    int i;
    for (i = 0; fread(&arr[i], sizeof(Candidate), 1, fp) == 1; i++)
        ;

    *number = i;
    return arr;
}

void print_sample_data(int number, Candidate *clist)
{
    for (int i = 0; i < number; i++)
    {
        printf("%-10s %-30s %.4d %.4d %s\n",
               clist[i].inscr, clist[i].name, clist[i].year,
               clist[i].position, clist[i].curse);
    }
}

Note that this produces the same data each time it is run, despite using the pseudo-random numbers from rand() . 请注意,尽管使用了rand()的伪随机数,但每次运行都会产生相同的数据。 Note too that the code deliberately exploits the behaviour of strncpy() that pads a field with null bytes to the full length so that the data in the file doesn't have any extraneous matter. 还要注意,该代码有意利用strncpy()的行为,该行为将具有空字节的字段strncpy()为完整长度,以便文件中的数据没有任何多余的内容。

Sample output: 样本输出:

I-0000     Name 0249 Surname 0807         2010 0099 Curse 73
I-0001     Name 0930 Surname 0658         2011 1098 Curse 72
I-0002     Name 0878 Surname 0544         2012 2097 Curse 23
I-0003     Name 0440 Surname 0709         2013 3096 Curse 65
I-0004     Name 0042 Surname 0492         2014 4095 Curse 87

Hex dump of data file: 数据文件的十六进制转储:

0x0000: 49 2D 30 30 30 30 00 00 00 00 4E 61 6D 65 20 30   I-0000....Name 0
0x0010: 32 34 39 20 53 75 72 6E 61 6D 65 20 30 38 30 37   249 Surname 0807
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0030: 00 00 00 00 00 00 00 00 DA 07 00 00 63 00 00 00   ............c...
0x0040: 43 75 72 73 65 20 37 33 00 00 00 00 00 00 00 00   Curse 73........
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0060: 49 2D 30 30 30 31 00 00 00 00 4E 61 6D 65 20 30   I-0001....Name 0
0x0070: 39 33 30 20 53 75 72 6E 61 6D 65 20 30 36 35 38   930 Surname 0658
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0090: 00 00 00 00 00 00 00 00 DB 07 00 00 4A 04 00 00   ............J...
0x00A0: 43 75 72 73 65 20 37 32 00 00 00 00 00 00 00 00   Curse 72........
0x00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00C0: 49 2D 30 30 30 32 00 00 00 00 4E 61 6D 65 20 30   I-0002....Name 0
0x00D0: 38 37 38 20 53 75 72 6E 61 6D 65 20 30 35 34 34   878 Surname 0544
0x00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00F0: 00 00 00 00 00 00 00 00 DC 07 00 00 31 08 00 00   ............1...
0x0100: 43 75 72 73 65 20 32 33 00 00 00 00 00 00 00 00   Curse 23........
0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0120: 49 2D 30 30 30 33 00 00 00 00 4E 61 6D 65 20 30   I-0003....Name 0
0x0130: 34 34 30 20 53 75 72 6E 61 6D 65 20 30 37 30 39   440 Surname 0709
0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0150: 00 00 00 00 00 00 00 00 DD 07 00 00 18 0C 00 00   ................
0x0160: 43 75 72 73 65 20 36 35 00 00 00 00 00 00 00 00   Curse 65........
0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0180: 49 2D 30 30 30 34 00 00 00 00 4E 61 6D 65 20 30   I-0004....Name 0
0x0190: 30 34 32 20 53 75 72 6E 61 6D 65 20 30 34 39 32   042 Surname 0492
0x01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x01B0: 00 00 00 00 00 00 00 00 DE 07 00 00 FF 0F 00 00   ................
0x01C0: 43 75 72 73 65 20 38 37 00 00 00 00 00 00 00 00   Curse 87........
0x01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x01E0:

There are 4 bytes of padding in the structures; 结构中有4个字节的填充。 2 after the name and 2 at the end, so its length is a convenient 96 bytes, which just happens to be a multiple of 16, so the hex dump aligns nicely. name后面加上2并在其末尾加上2,因此其长度为方便的96个字节,恰好是16的倍数,因此十六进制转储对齐得很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM