如果你需要读取二进制数据进入程序,那么你需要查看你尝试读取的内容。可以使用
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;
...
flts = xcalloc (MAXS, sizeof *flts);
while ((nbytes = fread (&buf, sizeof buf, 1, fp))) {
flts[idx] = calloc (1, sizeof **flts);
memcpy (flts[idx++], &buf, sizeof **flts);
if (idx == maxs)
flts = (flight **)xrealloc_dp((void *)flts, &maxs);
}
上面的代码为'flts'中的航班指针分配了一个初始数量,并使用静态结构体'buf'作为缓冲区从acars.bin文件中读取数据。当读取到'nbytes'并且非零时,会为存储在'flts[idx]'中的缓冲区分配内存,并使用'memcpy'将数据从'buf'复制到'flts[idx]'中(您应该添加验证以确保读取的内容是您预期的)。
使用标准的重新分配方案,先分配'maxs'个指向结构体的指针,达到该数量后,通过'xrealloc_dp'(这是一个简单的双指针宏实现的重新分配 - 您也可以使用一个简单的函数)将指针数重新分配为当前数量的两倍。这里的目的只是保持代码主体干净,以便逻辑不受所有'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));
}
这段代码涉及到it技术,其中flts[i]->tstamp
被转换为time_t
类型,并与其他航班数据一起使用ctime
提供格式化日期输出。
将所有部分组合在一起,理解xcalloc
和xrealloc_dp
只是用于calloc和realloc
的简单错误检查宏,您可以使用以下代码。 acars.bin
中包含2778
个航班数据,下面的代码仅打印前10个和后10个航班的数据:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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; \
})
#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); \
*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;
}
flts = xcalloc (MAXS, sizeof *flts);
while ((nbytes = fread (&buf, sizeof buf, 1, fp))) {
flts[idx] = calloc (1, sizeof **flts);
memcpy (flts[idx++], &buf, sizeof **flts);
if (idx == maxs)
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));
}
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个错误证实没有意外写入分配的内存块之外。
请查看代码,如果有任何问题,请告诉我,我很乐意提供进一步的帮助。
int
的大小(我们不知道),因此您会遇到问题。int FlightNum [7]
明显是错误的,因为航班号是字符。建议使用明确的类型,如int32_t
或适当的类型。 - hobbs