C语言中的二进制文件读写

3
我有一个 input.bin 文件,其中包含以下内容。
IK-SZH;jdl72u;John Doe;2013-03-28 11:05
IK-GRR;kat91n;Jane Doe;2013-03-21 15:41
IK-GRR;oat62f;Jane Doe;2013-03-24 08:08

我正在做的是将其读入结构体中。对数据进行一些处理。添加/删除行。 然后我想以与上述相同的格式将结构体的内容写回到input.bin文件中。
但是,它不像上面那样显示。它是这样的(没有空格):
IK-SZH NUL jdl72u NUL John Doe NUL NUL NUL NUL NUL 2013-03-28 NUL NUL NUL IK-GRR NUL kat91n NUL Jane Doe NUL NUL NUL NUL ...

当我重新读取(带有NULs的)文件时,它只将第一行放入结构体中。
我的代码:
typedef struct foo {
    char kid[7];    
    char jid[7];    
    char name[21];  
    char time[20];  

} Foo;

Foo foo[200];
FILE* fp;
int size;

------- 文件阅读器
void read(char* filename){
    fp = fopen(filename, "rb"); 
    int i = 0;

    while (!feof(fp)) {

        if (fp==NULL){perror("File opening error\n"); exit(1);}

        fscanf(fp,"%[^;]; %[^;]; %20[^\;]; %s\n", foo[i].kid, foo[i].jid,
                foo[i].name, foo[i].time);
        i++;
    }

    size = i;

    print();

    fclose(fp);
}


void print(){
    int i;
    for (i = 0; i < size; ++i){
        printf("%s\t %s\t %s\t %s\n", foo[i].kid, foo[i].jid,
               foo[i].name, foo[i].time);
    }
}

----- 作者

void write(){
    char str[1000];

    FILE* f = fopen("input.bin", "wb");
    fseek(f, 0, SEEK_SET);
    int i;
    for (i = 0; i < jel_size; i++)
            fwrite(&foo[i], sizeof(struct foo), 1, f);
    fclose(f);

}

尝试了这个方法,但是它没有向文件中写入任何内容:
    char str[1000];
    sprintf(str,"%s;%s;%s;%s\n", jelent[i].kazon,
                    jelent[i].jazon,jelent[i].nev,  jelent[i].ido );

        write(f,&str,sizeof(str))!=sizeof(str);

6
输入文件 input.bin 看起来像是一个文本文件而不是二进制文件。 - Marcos
1
你可能需要考虑使用fprintf()而不是fwrite()或write()。 - Mackie Messer
你应该以文本模式而非二进制模式打开文本文件。 - Code-Apprentice
2个回答

5

您的结构定义如下:

typedef struct foo
{
    char kid[7];    
    char jid[7];    
    char name[21];  
    char time[20];  
} Foo;

将结构写入文件的代码在write()中:

for (i = 0; i < jel_size; i++)
    fwrite(&foo[i], sizeof(struct foo), 1, f);

如果结构体被初始化为所有字节都是零,那么对于数据的第一行,您可以这样提到:
IK-SZH;jdl72u;John Doe;2013-03-28 11:05

我们可以推断出这个结构包含了:
IK-SZH\0
jdl72u\0
John Doe\0\0\0\0\0\0\0\0\0\0\0\0\0
2013-03-28 11:05\0\0\0\0

这基本上与您所说的文件内容相符:

IK-SZH NUL jdl72u NUL John Doe NUL NUL NUL NUL NUL 2013-03-28 NUL NUL NUL 

根据我的计算,您在名称、时间和日期后面缺少几个NUL,并且日期后面还需要一个NUL。
如果您想要文本输出,您需要在write()中使用fprintf()对数据进行格式化,类似于您在read()函数中使用fscanf()语句。您应该从函数中返回状态以指示是否成功。您也可以考虑检查fclose()是否成功。
void write(void)
{
    FILE *fp = fopen("input.bin", "w");
    if (fp != 0)
    {
        for (int i = 0; i < jel_size; i++)
            fprintf(fp, "%s;%s;%s;%s\n", foo[i].kid, foo[i].jid, foo[i].name, foo[i].time);
        fclose(fp);
    }
}

如果您希望得到二进制输出,应该在read()中使用二进制输入。同样,您应该考虑返回成功或失败的指示;避免使用全局变量也是不错的选择。

void read(const char *filename)
{
    FILE *fp = fopen(filename, "rb"); 
    if (fp != 0)
    {
        for (i = 0; fread(&foo[i], sizeof(foo[i]), 1, fp) == 1; i++)
            ;
        fclose(fp);
        size = i;
    }
}

无论哪种技术都可以使用;试图在输出中使用一种技术,在输入中使用另一种技术将导致混乱和困惑。
请注意,函数read()和write()在POSIX中具有不同的接口。 在您坚持使用标准C时,这些名称对您来说是合适的,但最好使用替代名称,例如reader()和writer()或foo_read()和foo_write()。

简直不敢相信我没想到用fprintf。我已经知道fread、fwrite的事情了,只是不想使用它们,因为文件中有分号分隔符,不确定如何解决这个问题。非常感谢您的帮助! - vzkiss

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接