gpt4 book ai didi

c - 逐条记录地从二进制文件中读取数据

转载 作者:太空宇宙 更新时间:2023-11-03 23:25:51 25 4
gpt4 key购买 nike

我正在尝试制作一个数据库,暂时保存一些关于团队的数据。问题是我无法逐条读取输入的数据。我想用一个例子来解释它:

insert manunited,manchester,old_trafford,1878,black-rd to teams
insert chelsea,london,stamford_bridge,1905,blue-whte to teams
select colors,team_name,founding_date from teams

选择在屏幕上打印指定的信息,即颜色、体育场等。

insert暂时带队信息,所以根据select命令,输出应该是:

black-rd   manunited    1878
blue-whte chelsea 1905

但是,我明白了

black-rd   manunited    1878   blue-whte

几个小时以来,我一直在尝试分析我的错误。我找不到错误和错误。感谢您提供所有赞赏的答案。顺便说一下,我还没有使用 while 循环来插入或选择命令。我正在考虑找出错误。

代码:

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

typedef struct
{
char team_name[TEAM_NAME];
char city[TEAM_NAME];
char stadium[STADIUM_NAME];
int founding_date;
char colors[COLOR];
}teams;

int main()
{

char read_command[12];
/* checking insert */
char str1[100],str2[5],str3[18];
FILE *fptr;
teams t;

scanf("%s", read_command);

if(strcmp(read_command,"insert") == 0)
{
scanf("%s %s %s", str1, str2, str3);
//printf("%s\n%s\n%s",str1,str2,str3);
insertfunc(fptr,str1, str2, str3);

}
if(strcmp(read_command,"select") == 0)
{
scanf("%s %s %s", str1, str2, str3);
selectfunc(fptr,str1, str2, str3);
}

return 0;
}

void selectfunc(FILE *fptr,char *str1,char *str2,char *str3)
{
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff,str1);
char *token;

const char comma[2] = ",";

if(strcmp(str3,"teams") == 0)
{
teams t;

fptr = fopen("teams.bin","rb");

if( fptr == NULL )
{
perror("File cannot be opened.");
exit(1);
}
else
{
while(fread(&t,sizeof(teams),1,fptr) == 1)
{
/* get the first token */
token = strtok(buff, comma);

while( token != NULL )
{
if(strcmp(token,"team_name") == 0)
{
printf(" %s ",t.team_name);
}
else if(strcmp(token,"city") == 0)
{
printf(" %s ",t.city);
}
else if(strcmp(token,"stadium") == 0)
{
printf(" %s ",t.stadium);
}
else if(strcmp(token,"colors") == 0)
{
printf(" %s ",t.colors);
}
else
{
printf(" %d ",t.founding_date);
}

token = strtok(NULL, comma);
}
}
}
fclose(fptr);
}


}


void insertfunc(FILE *fptr,char *str1,char *str2,char *str3)
{
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff,str1);

const char comma[2] = ",";

/*
if(buff == NULL)
perror("error");
*/

if(strcmp(str3,"teams") == 0)
{
teams t;
int date;

strcpy(t.team_name,strtok(buff, comma));
strcpy(t.city, strtok(NULL, comma));
strcpy(t.stadium, strtok(NULL, comma));
date = atoi(strtok(NULL, comma));
t.founding_date = date;
strcpy(t.colors, strtok(NULL, comma));

fptr = fopen("teams.bin","ab+");

if( fptr == NULL )
{
perror("File cannot be opened.");
exit(1);
}
else
{
fwrite(&t,sizeof(teams),1,fptr);
fclose(fptr);
}
}
free(buff);
}

最佳答案

下面的工作代码。

除了构建所需的更改(主要是定义结构字段的大小)之外,dump_teams()函数用于记录团队记录中的信息,err_exit()函数简洁地报告错误。您的错误检查没有改变。我主要反对 perror()是你通常得不到报告的关键信息,例如未打开的文件名。升级不难err_exit()报告系统错误以及有意义的消息(例如 failed to open file "teams.bin": No such file or directory )——OP 练习。这些函数用于验证信息,并确保检测到意外的拼写。请注意,调试中的字段值包含在双尖括号中 <<…info…>> ;这使得更容易发现各种问题,例如前导或尾随空格,或 '\r'输入数据中的字符。 assert()确保 str2用于两个主要功能。选择数据格式变得更加统一。有一个名字 data_file保存数据文件名。

关键错误修复在 selectfunc() 中循环,其中 str1 的值被复制到buff为每条记录重新生成。

这是一种懒惰的工作方式;最好对字符串进行一次预解析,然后使用预解析生成的数据结构遍历数据记录。当然,如果有数百万条记录,这比只有 2 条记录更重要。

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

enum { TEAM_NAME = 20, STADIUM_NAME = 20, COLOR = 20 };

static const char data_file[] = "teams.bin";

typedef struct
{
char team_name[TEAM_NAME];
char city[TEAM_NAME];
char stadium[STADIUM_NAME];
int founding_date;
char colors[COLOR];
} teams;

void insertfunc(char *str1, char *str2, char *str3);
void selectfunc(char *str1, char *str2, char *str3);
void err_exit(const char *fmt, ...);
void dump_teams(FILE *fp, const char *tag, const teams *team);

int main(void)
{
char read_command[12];
char str1[100], str2[5], str3[18];

if (scanf("%s", read_command) != 1)
err_exit("read for command failed");
else if (strcmp(read_command, "insert") == 0)
{
if (scanf("%99s %4s %17s", str1, str2, str3) != 3)
err_exit("read for insert failed");
insertfunc(str1, str2, str3);
}
else if (strcmp(read_command, "select") == 0)
{
if (scanf("%99s %4s %17s", str1, str2, str3) != 3)
err_exit("read for select failed");
selectfunc(str1, str2, str3);
}
else
err_exit("Unrecognized command <<%s>>", read_command);

return 0;
}

void selectfunc(char *str1, char *str2, char *str3)
{
FILE *fptr;
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
char *token;

fprintf(stderr, "select: <<%s>> <<%s> <<%s>>\n", str1, str2, str3);
assert(strcmp(str2, "from") == 0);

const char comma[2] = ",";

if (strcmp(str3, "teams") == 0)
{
teams t;

fptr = fopen(data_file, "rb");

if (fptr == NULL)
{
perror("File cannot be opened.");
exit(1);
}
else
{
while (fread(&t, sizeof(teams), 1, fptr) == 1)
{
dump_teams(stderr, "select", &t);
strcpy(buff, str1);
/* get the first token from command str1 */
token = strtok(buff, comma);

while (token != NULL)
{
fprintf(stderr, "token = <<%s>>\n", token);
if (strcmp(token, "team_name") == 0)
{
printf(" %-20s", t.team_name);
}
else if (strcmp(token, "city") == 0)
{
printf(" %-20s", t.city);
}
else if (strcmp(token, "stadium") == 0)
{
printf(" %-20s", t.stadium);
}
else if (strcmp(token, "colors") == 0)
{
printf(" %-20s", t.colors);
}
else if (strcmp(token, "founding_date") == 0)
{
printf(" %d", t.founding_date);
}
else
err_exit("Unrecognized field name <<%s>>", token);

token = strtok(NULL, comma);
}
putchar('\n');
}
}
fclose(fptr);
}
else
err_exit("Unrecognized data source <<%s>>", str3);
}

void insertfunc(char *str1, char *str2, char *str3)
{
FILE *fptr;
char *buff;
buff = (char*) malloc(strlen(str1) + 1);
strcpy(buff, str1);

fprintf(stderr, "select: <<%s>> <<%s> <<%s>>\n", str1, str2, str3);
assert(strcmp(str2, "to") == 0);

const char comma[2] = ",";

if (strcmp(str3, "teams") == 0)
{
teams t;
int date;

strcpy(t.team_name, strtok(buff, comma));
strcpy(t.city, strtok(NULL, comma));
strcpy(t.stadium, strtok(NULL, comma));
date = atoi(strtok(NULL, comma));
t.founding_date = date;
strcpy(t.colors, strtok(NULL, comma));
dump_teams(stderr, "insert", &t);

fptr = fopen(data_file, "ab+");

if (fptr == NULL)
{
perror("File cannot be opened.");
exit(1);
}
else
{
if (fwrite(&t, sizeof(teams), 1, fptr) != 1)
err_exit("fwrite failed");
fclose(fptr);
}
}
else
err_exit("Unrecognized data destination <<%s>>", str3);
free(buff);
}

void dump_teams(FILE *fp, const char *tag, const teams *team)
{
assert(fp != 0 && tag != 0 && team != 0);
fprintf(fp, "%s\n", tag);
fprintf(fp, "%8s: <<%s>>\n", "Team", team->team_name);
fprintf(fp, "%8s: <<%s>>\n", "City", team->city);
fprintf(fp, "%8s: <<%s>>\n", "Stadium", team->stadium);
fprintf(fp, "%8s: <<%d>>\n", "Founded", team->founding_date);
fprintf(fp, "%8s: <<%s>>\n", "Colours", team->colors);
fflush(fp);
}

#include <stdarg.h>

void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
putc('\n', stderr);
exit(EXIT_FAILURE);
}

示例输出

文件 cmd1 , cmd2cmd3包含问题中的三个命令行。

$ ./rw < cmd1
select: <<manunited,manchester,old_trafford,1878,black-red>> <<to> <<teams>>
insert
Team: <<manunited>>
City: <<manchester>>
Stadium: <<old_trafford>>
Founded: <<1878>>
Colours: <<black-red>>
$ ./rw < cmd2
select: <<chelsea,london,stamford_bridge,1905,blue-white>> <<to> <<teams>>
insert
Team: <<chelsea>>
City: <<london>>
Stadium: <<stamford_bridge>>
Founded: <<1905>>
Colours: <<blue-white>>
$ ./rw < cmd3
select: <<colors,team_name,founding_date>> <<from> <<teams>>
select
Team: <<manunited>>
City: <<manchester>>
Stadium: <<old_trafford>>
Founded: <<1878>>
Colours: <<black-red>>
token = <<colors>>
token = <<team_name>>
token = <<founding_date>>
black-red manunited 1878
select
Team: <<chelsea>>
City: <<london>>
Stadium: <<stamford_bridge>>
Founded: <<1905>>
Colours: <<blue-white>>
token = <<colors>>
token = <<team_name>>
token = <<founding_date>>
blue-white chelsea 1905
$ ./rw < cmd3 2>/dev/null
black-red manunited 1878
blue-white chelsea 1905
$

请注意,通过将调试信息放在标准错误上,可以很容易地将调试信息与正常输出分开,就像上次运行一样。

关于c - 逐条记录地从二进制文件中读取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27647317/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com