所以它给我的全部是十六进制编辑器打印输出,前4个字节是整数,说明有多少个日期,然后是字符MMDDYY,每个日期有6个字符。我如何编写一个读取.bin文件的程序将前4个字节(int)作为元素的数量,然后读入每个日期,解析出14年的日期?
这样的东西?
int void main(void) {
FILE* infile = fopen("dates.bin", "rb");
int numOfDates;
fgets(numOfDates, sizeof(int), infile);
int i, totalDates;
char allDates[numOfDates * 6];
for(i = 0; i <= numOfDates; i++) {
char tempDate[6];
fgets(tempDate, sizeof(tempDate), infile);
if(tempDate[5] == '1' && tempDate[6] == '4') {
strcpy(allDates[totalDates * 6], tempDate);
totalDates++;
}
}
fclose(infile);
int j;
FILE* outfile = fopen("datesNew.bin", "wb");
fprintf(outfile, "%d", totalDates);
fprintf(outfile, "%s", allDates);
fclose(outfile);
}
答案 0 :(得分:1)
你所拥有的任务就是必须逐步逐步验证每个输入和输出。只有这样,您才能对输入和输出有信心。有一点需要注意,我怀疑这是你的课程中的故意,输入文件中的日期比文件中第一个整数所包含的数字要多。 (数字是7,但文件实际上包含8个日期)
通常,但并非总是如此,您可以将阅读和写作结构化为单独的操作。在这里,由于您必须以与输入文件相同的格式重新创建输出文件(输出中包含的2014日期数作为写入文件的第一个整数值),您几乎必须以这种方式有效地执行此操作单个传递输入文件。 (您总是可以多次读取您的输入,但从效率的角度来看,这是您想要避免的 - 磁盘I / O是主要瓶颈)
正如我在评论main()
中指出的那样是类型int
,它接受参数,使用它们将文件名传递给您的代码。归类为int
,main()
因此returns
为值。
您的第一个任务是打开输入文件并读取您希望从文件中读取的日期数。这可以从一个简单的开始:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define DTSZ 6
int main (int argc, char **argv) {
FILE *fp = NULL; /* file pointer to use for both read/write */
int32_t n = 0; /* number of dates to read from input */
if (argc < 3) { /* validate input/output filenames arguments given */
fprintf (stderr, "error: insufficient input.\n"
"usage: %s infile.bin outfile.bin\n", argv[0]);
return 1;
}
if (!(fp = fopen (argv[1], "rb"))) { /* input file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (fread (&n, sizeof n, 1, fp) != 1) { /* read number of dates */
fprintf (stderr, "error: read of n-dates failed.\n");
return 1;
}
由于您现在知道要读取的日期数,因此可以使用可变长度数组(VLA)来保存日期。提前考虑,您还需要跟踪哪些日期为2014
个日期,以便创建一个长度为chk
的支票n
数组并初始化为所有零将允许您在chk
中增加与2014
对应的索引,这样一旦确定了有多少个2014
日期,就可以使用该机制将 char buf[n][DTSZ + 1]; /* +1 to allow use as string */
int32_t chk[n], n14 = 0; /* array for 2014 indexes, number */
memset (chk, 0, sizeof chk); /* zero the chk array */
for (int i = 0; i < n; i++) { /* read/validate each date */
if (fread (buf[i], 1, DTSZ, fp) != DTSZ) {
fprintf (stderr, "error: failed to read date '%d'.\n", i);
return 1;
}
buf[i][DTSZ] = 0; /* nul-terminate for string use */
printf ("read : %s\n", buf[i]); /* output date found */
if (buf[i][4] == '1' && buf[i][5] == '4') /* 2014 ? */
n14++, chk[i]++; /* increment count, index */
}
fclose (fp); /* close input file */
日期写入输出文件。因此,在创建VLA之后,您可以循环输入的日期数量,将它们存储在一个数组中,在输入完成后关闭文件,例如
2014
现在,知道日期缓冲区中chk
日期的数量和这些日期的索引,您可以打开输出文件,循环buf
中的索引,输出{{1}中的日期对应于chk
中的集索引,例如
if (!(fp = fopen (argv[2], "wb"))) { /* output file open */
fprintf (stderr, "error: file open failed '%s'.\n", argv[2]);
return 1;
}
if (fwrite (&n14, sizeof n14, 1, fp) != 1) { /* output n 2014 */
fprintf (stderr, "error: write of n14-dates failed.\n");
return 1;
}
for (int i = 0; i < n; i++) /* for each date read */
if (chk[i]) { /* check 2014 index */
printf ("write : '%s' to output.\n", buf[i]);
if (fwrite (buf[i], 1, DTSZ, fp) != DTSZ) { /* write/validate */
fprintf (stderr, "error: write of '%s' failed.\n", buf[i]);
return 1;
}
}
if (fclose (fp) == EOF) { /* close output file */
/* handle error */
}
return 0;
}
注意:您还应在执行写操作后检查return
的{{1}}。 fclose
成功时返回fclose
或错误时返回0
,并设置EOF
以包含有关遇到的错误的详细信息。检查errno
就足够了。担心的是,先前的写入操作可能遇到了在流关闭,关闭本身被中断或发生IO错误之前未报告的错误。另请注意,if (fclose (fp) == EOF) {/*... handle error ...*/}
不会导致数据在所有情况下都立即写入磁盘(内核可能会缓冲输出等)。要强制立即写入磁盘,请调用fclose
以确保刷新缓冲区并写入数据。
将这些部分放在一起,您可以期待以下内容:
示例使用/输出
fsync
验证书面文件
$ ./bin/freaddates dat/bindates.bin dat/newdates.bin
read : 050514
read : 032313
read : 012514
read : 081612
read : 073114
read : 020612
read : 112315
write : '050514' to output.
write : '012514' to output.
write : '073114' to output.
仔细看看,如果您有任何其他问题,请告诉我。