如果您要将二进制数据读入您的程序,那么您需要查看并查看您正在尝试读取的内容。 hexdump 或 od 是查看数据的绝佳工具:
$ hexdump -C -n 512 dat/acars.bin
00000000 59 56 32 38 32 37 00 4b 43 4c 54 00 4b 53 52 51 |YV2827.KCLT.KSRQ|
00000010 00 00 00 00 2c 83 d0 52 59 56 32 37 38 32 00 4b |....,..RYV2782.K|
00000020 43 4c 54 00 4b 53 52 51 00 00 00 00 cc 3e ed 52 |CLT.KSRQ.....>.R|
00000030 59 56 32 37 33 32 00 4b 43 4c 54 00 4b 53 52 51 |YV2732.KCLT.KSRQ|
00000040 00 00 00 00 88 f4 d5 52 59 56 32 36 37 35 00 4b |.......RYV2675.K|
00000050 43 4c 54 00 4b 53 52 51 00 00 00 00 20 57 9f 52 |CLT.KSRQ.... W.R|
00000060 59 34 39 38 34 31 00 4b 4d 43 4f 00 4d 4d 4d 58 |Y49841.KMCO.MMMX|
根据您的描述,您有航班号、出发机场、目的地机场和时间戳。查看数据,您会发现航班号 YV2827(以空结尾),您有 KCLT,这是夏洛特/道格拉斯国际机场的 IACO 标识符。机场,下一个 KSRQ(佛罗里达州萨拉索塔机场的 IACO 标识符),几个字节的填充,最后是一个代表时间戳的 4 字节数字。所以数据文件是有意义的。
现在怎么读?如果您的描述成立,那么保存元素的结构应该提供一种读取数据的方法。您可能必须与不同的成员和不同的 属性 合作才能使填充工作,但接近以下的东西应该可以工作:
typedef struct {
char flight[7];
char dept[5];
char dest[5];
unsigned tstamp;
} flight;
接下来,如何读取文件并将值存储在代码中的内存中。如果您不需要存储这些值,那么只需简单地读取和打印数据即可。假设您需要存储它以实际使用数据,那么在不知道acars.bin 中包含多少航班的情况下,您将需要一个方案来读取/分配内存来保存数据。
一种灵活的方法是使用静态缓冲区来读取每个航班,然后使用malloc/calloc 分配一个指向航班的指针数组,并根据需要使用realloc 来保存航班数据。比如:
flight buf = {{0}, {0}, {0}, 0};
flight **flts = NULL;
size_t idx = 0;
size_t nbytes = 0;
...
/* allocate MAXS pointers to flight */
flts = xcalloc (MAXS, sizeof *flts);
/* read into buf until no data read, allocate/copy to flts[i] */
while ((nbytes = fread (&buf, sizeof buf, 1, fp))) {
flts[idx] = calloc (1, sizeof **flts);
memcpy (flts[idx++], &buf, sizeof **flts);
if (idx == maxs) /* if pointer limit reached, realloc */
flts = (flight **)xrealloc_dp((void *)flts, &maxs);
}
上面,代码在'flts'中分配了一个初始数量的指向飞行的指针,并使用静态结构buf作为缓冲区从acars.bin文件中读取数据。在读取nbytes 且非零时,分配内存用于存储flts[idx] 中的缓冲区,memcpy 用于将数据从buf 复制到flts[idx]。 (您应该添加验证,以确保所读取的内容实际上是您所期望的)。
使用标准的重新分配方案,首先将maxs 指针分配给结构,当达到该数量时,指针的数量通过xrealloc_dp 重新分配为当前数量的两倍(这是一个简单的双精度重新分配-pointer 宏——你也可以使用一个简单的函数)这里的目的只是为了保持代码的主体干净,这样逻辑就不会被所有realloc 验证代码等所掩盖。
在完整读取 acars.bin 之后,您将所有值存储在 flts 中(注意时间戳存储为 unsigned int 值,因此转换为日历时间类型并格式化输出留待你的输出例程)。输出的简单重新格式化可能是:
for (i = 0; i < 10; i++) {
time_t fdate = (time_t)flts[i]->tstamp;
printf (" flight[%4zu] %-8s %-5s %-5s %s", i, flts[i]->flight,
flts[i]->dept, flts[i]->dest, ctime (&fdate));
}
其中flts[i]->tstamp 被转换为time_t,然后与ctime 一起使用以提供格式化的日期以与其余的航班数据一起输出。
将所有部分放在一起,了解xcalloc 和xrealloc_dp 只是calloc 和realloc 的简单错误检查宏,您可以使用类似以下的内容。 2778 包含在 acars.bin 中的航班,下面的代码仅打印前 10 个和最后 10 个航班的数据:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* calloc with error check - exits on any allocation error */
#define xcalloc(nmemb, size) \
({ void *memptr = calloc((size_t)nmemb, (size_t)size); \
if (!memptr) { \
fprintf(stderr, "error: virtual memory exhausted.\n"); \
exit(EXIT_FAILURE); \
} \
memptr; \
})
/* realloc with error check - exits on any allocation error */
#define xrealloc_dp(ptr,nmemb) \
({ \
void **p = ptr; \
size_t *n = nmemb; \
void *tmp = realloc (p, 2 * *n * sizeof tmp); \
if (!tmp) { \
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); \
exit (EXIT_FAILURE); \
} \
p = tmp; \
memset (p + *n, 0, *n * sizeof tmp); /* set new pointers NULL */ \
*n *= 2; \
p; \
})
#define MAXS 256
typedef struct {
char flight[7];
char dept[5];
char dest[5];
unsigned tstamp;
} flight;
int main (int argc, char **argv) {
flight buf = {{0}, {0}, {0}, 0};
flight **flts = NULL;
size_t idx = 0;
size_t nbytes = 0;
size_t maxs = MAXS;
size_t i, index;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* allocate MAXS pointers to flight */
flts = xcalloc (MAXS, sizeof *flts);
/* read into buf until no data read, allocate/copy to flts[i] */
while ((nbytes = fread (&buf, sizeof buf, 1, fp))) {
flts[idx] = calloc (1, sizeof **flts);
memcpy (flts[idx++], &buf, sizeof **flts);
if (idx == maxs) /* if pointer limit reached, realloc */
flts = (flight **)xrealloc_dp((void *)flts, &maxs);
}
if (fp != stdin) fclose (fp);
printf ("\n There are '%zu' flights in acars data.\n", idx);
printf ("\n The first 10 flights are:\n\n");
for (i = 0; i < 10; i++) {
time_t fdate = (time_t)flts[i]->tstamp;
printf (" flight[%4zu] %-8s %-5s %-5s %s", i, flts[i]->flight,
flts[i]->dept, flts[i]->dest, ctime (&fdate));
}
printf ("\n The last 10 flights are:\n\n");
index = idx - 10;
for (i = index; i < idx; i++) {
time_t fdate = (time_t)flts[i]->tstamp;
printf (" flight[%4zu] %-8s %-5s %-5s %s", i, flts[i]->flight,
flts[i]->dept, flts[i]->dest, ctime (&fdate));
}
/* free memory */
for (i = 0; i < idx; i++)
free (flts[i]);
free (flts);
return 0;
}
输出
$ ./bin/readacars dat/acars.bin
There are '2778' flights in acars data.
The first 10 flights are:
flight[ 0] YV2827 KCLT KSRQ Fri Jan 10 17:33:00 2014
flight[ 1] YV2782 KCLT KSRQ Sat Feb 1 12:37:00 2014
flight[ 2] YV2732 KCLT KSRQ Tue Jan 14 20:38:00 2014
flight[ 3] YV2675 KCLT KSRQ Wed Dec 4 10:24:00 2013
flight[ 4] Y49841 KMCO MMMX Tue Jul 23 13:25:00 2013
flight[ 5] Y45981 KMCO MMMX Wed Feb 26 13:31:00 2014
flight[ 6] Y45980 MMMX KMCO Tue Mar 25 13:49:00 2014
flight[ 7] Y40981 KMCO MMMX Wed Mar 5 13:23:00 2014
flight[ 8] Y40980 MMMX KMCO Sat Mar 29 11:38:00 2014
flight[ 9] XX0671 KJFK MSLP Tue Mar 25 05:46:00 2014
The last 10 flights are:
flight[2768] 4O2993 KJFK MMMX Wed Feb 12 09:25:00 2014
flight[2769] 1L9221 KSAT KSFB Thu Jan 9 15:41:00 2014
flight[2770] 1L1761 KCID KSFB Tue Jan 14 13:11:00 2014
flight[2771] 1L1625 KABE KSFB Thu Jan 16 10:22:00 2014
flight[2772] 1L0751 KMFE KSFB Thu Jan 16 19:52:00 2014
flight[2773] 1L0697 KTYS KSFB Wed Jan 15 10:21:00 2014
flight[2774] 1L0696 KSFB KTYS Wed Jan 15 07:00:00 2014
flight[2775] 1L0655 KIAG KSFB Fri Jan 17 21:11:00 2014
flight[2776] 1L0654 KSFB KIAG Fri Jan 17 15:49:00 2014
flight[2777] 1L0641 KGFK KSFB Fri Jan 17 14:21:00 2014
内存错误/泄漏检查
在您编写的动态分配内存的任何代码中,您必须使用内存错误检查程序来确保您没有写入超出分配的内存并确认您已释放所有已分配的内存。对于 Linux,valgrind 是正常的选择。滥用内存块有很多微妙的方法可能导致真正的问题,没有理由不这样做。每个平台都有类似的内存检查器。它们使用简单。只需通过它运行您的程序即可。
$ valgrind ./bin/readacars dat/acars.bin
==12304== Memcheck, a memory error detector
==12304== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==12304== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==12304== Command: ./bin/readacars dat/acars.bin
==12304==
There are '2778' flights in acars data.
The first 10 flights are:
flight[ 0] YV2827 KCLT KSRQ Fri Jan 10 17:33:00 2014
flight[ 1] YV2782 KCLT KSRQ Sat Feb 1 12:37:00 2014
flight[ 2] YV2732 KCLT KSRQ Tue Jan 14 20:38:00 2014
<snip>
flight[2776] 1L0654 KSFB KIAG Fri Jan 17 15:49:00 2014
flight[2777] 1L0641 KGFK KSFB Fri Jan 17 14:21:00 2014
==12304==
==12304== HEAP SUMMARY:
==12304== in use at exit: 0 bytes in 0 blocks
==12304== total heap usage: 2,812 allocs, 2,812 frees, 134,011 bytes allocated
==12304==
==12304== All heap blocks were freed -- no leaks are possible
==12304==
==12304== For counts of detected and suppressed errors, rerun with: -v
==12304== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
134,011 分配的字节数和所有堆块均已释放——不可能有泄漏 确认您正在释放您分配的所有内存。 错误摘要:来自 0 个上下文的 0 个错误确认在分配的内存块之外没有无意写入。
查看代码,如果您有任何问题,请告诉我,我很乐意为您提供进一步帮助。