如何在 C 中使用 'fread' 从文件中读取和获取分离的数据?
How can I read and obtain separated data from a file using 'fread' in C?
我在文件中写入了(使用“fwrite()”)以下内容:
TUS�ABQ���������������(A����������(A��B������(A��B���A��(A��B���A������B���A������0����A������0�ABQ�������0�ABQ�����LAS����������������A�����������A��&B�������A��&B��B���A��&B��B������&B��
B����153���B����153�LAS�����153�LAS�����LAX���������������:A����������:AUUB������:AUUB��B��:
AUUB��B����UUB��B����������B��������LAX���������LAX�����MDW���������������A����������A��(�������A��(����A��A��(����A������(����A����A�89���A����A�89MDW�����A�89MDW�����OAK���������
����������������������@�����������@�����������@�����������@�������������������������OAK���������OAK�����SAN���������������LA����������LA��P@������LA��P@��@A��LA��P@��@A������P@��@A����������@A��������SAN���������SAN�����TPA�ABQ����������������B�����������B��@�����...(continues)
翻译为:
TUSLWD2.103.47.775.1904.06.40.03AMBRFD4.63.228.935.0043.09.113.0ASDGHU5.226.47.78.3.26...(The same structure)
其 hexdump 为:
00000000 54 55 53 00 41 42 51 00 00 00 00 00 00 00 00 00 |TUS.ABQ.........|
00000010 00 00 00 00 00 00 28 41 00 00 0e 42 00 00 f8 41 |......(A...B...A|
00000020 00 00 00 00 4c 41 53 00 00 00 00 00 00 00 00 00 |....LAS.........|
00000030 00 00 00 00 00 00 88 41 00 00 26 42 9a 99 11 42 |.......A..&B...B|
(Continues...)
结构是,总是 2 个单词,每个单词 3 个字符(即 TUS 和 LWD)后跟 7 个浮点数,然后它再次重复直到文件结束。
关键是:我只想读取每个字段,如 'TUS'、'LWD'、'2.10'、'3.4'、'7.77'...
而且我只能使用“fread()”来实现!现在,我正在尝试这个:
aux2 = 0;
fseek(fp, SEEK_SET, 0);
fileSize = 0;
while (!feof(fp) && aux<=2) {
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
for(i=0; i<7; i++){
fread(&delay, sizeof(float), 1, fp);
printf("%f", delay);
}
printf("\n");
aux++;
fseek(fp,sizeof(char)*7+sizeof(float)*7,SEEK_SET);
aux2+=36;
}
我得到了这个结果:
TUSABQ0.0000000.0000000.00000010.5000000.0000000.00000010.500000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
但它不能正常工作...
*注意:忘记最后'fseek()'的参数,因为我已经尝试了太多没有意义的事情!
要将单词(即 TUS)写入文件,我使用:
fwrite(x->data->key, 4, sizeof(char), fp);
为了写浮点数,这个:
for (i = 0; i < 7; i++) {
fwrite(¤t->data->retrasos[i], sizeof(float), sizeof(float), fp);
}
我建议使用一个结构来保存每个数据单元:
typedef struct {
float value[7];
char word1[5]; /* 4 + '[=10=]' */
char word2[5]; /* 4 + '[=10=]' */
} unit;
为了使文件格式可移植,您需要一个函数来打包和解包上述结构 to/from 一个 36 字节的数组。在 Intel 和 AMD 架构上,float
对应于 IEEE-754-2008 binary32 格式的小端字节序。例如,
#define STORAGE_UNIT (4+4+7*4)
#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
size_t unit_pack(char *target, const size_t target_len, const unit *source)
{
size_t i;
if (!target || target_len < STORAGE_UNIT || !source) {
errno = EINVAL;
return 0;
}
memcpy(target + 0, source->word1, 4);
memcpy(target + 4, source->word2, 4);
for (i = 0; i < 7; i++)
memcpy(target + 8 + 4*i, &(source->value[i]), 4);
return STORAGE_UNIT;
}
size_t unit_unpack(unit *target, const char *source, const size_t source_len)
{
size_t i;
if (!target || !source || source_len < STORAGE_UNIT) {
errno = EINVAL;
return 0;
}
memcpy(target->word1, source, 4);
target->word1[4] = '[=11=]';
memcpy(target->word2, source + 4, 4);
target->word2[4] = '[=11=]';
for (i = 0; i < 7; i++)
memcpy(&(target->value[i]), source + 8 + i*4, 4);
return STORAGE_UNIT;
}
#else
#error Unsupported architecture!
#endif
以上仅适用于 Intel 和 AMD 机器,但如果需要,很容易扩展到其他架构。 (目前几乎所有机器都使用 IEEE 754-2008 binary32 float
,只是字节顺序有所不同。那些不使用的机器通常有 C 扩展来转换 to/from 它们的内部格式。)
使用上面的方法,你可以——应该!必须! -- 记录你的文件格式,例如如下:
Words are 4 bytes encoded in UTF-8
Floats are IEEE 754-2008 binary32 values in little-endian byte order
A file contains one or more units. Each unit comprises of
Name Description
word1 First word
word2 Second word
value0 First float
value1 Second float
value2 Third float
value3 Fourth float
value4 Fifth float
value5 Sixth float
value6 Second float
There is no padding.
要写一个单元,使用大小为STORAGE_UNIT
的char
数组作为缓存,然后写那个。因此,如果您有 unit *one
,您可以使用
将其写入 FILE *out
char buffer[STORAGE_UNIT];
if (unit_pack(buffer, sizeof buffer, one)) {
/* Error! Abort program! */
}
if (fwrite(buffer, STORAGE_UNIT, 1, out) != 1) {
/* Write error! Abort program! */
}
相应地,从 FILE *in
读取将是
char buffer[STORAGE_UNIT];
if (fread(buffer, STORAGE_UNIT, 1, in) != 1) {
/* End of file, or read error.
Check feof(in) or/and ferror(in). */
}
if (unit_unpack(one, buffer, STORAGE_UNIT)) {
/* Error! Abort program! */
}
如果 one
是 unit
的数组,并且您正在写入或读取 one[k]
,请改用 &(one[k])
(或等效的 one + k
) one
.
我在文件中写入了(使用“fwrite()”)以下内容:
TUS�ABQ���������������(A����������(A��B������(A��B���A��(A��B���A������B���A������0����A������0�ABQ�������0�ABQ�����LAS����������������A�����������A��&B�������A��&B��B���A��&B��B������&B��
B����153���B����153�LAS�����153�LAS�����LAX���������������:A����������:AUUB������:AUUB��B��:
AUUB��B����UUB��B����������B��������LAX���������LAX�����MDW���������������A����������A��(�������A��(����A��A��(����A������(����A����A�89���A����A�89MDW�����A�89MDW�����OAK���������
����������������������@�����������@�����������@�����������@�������������������������OAK���������OAK�����SAN���������������LA����������LA��P@������LA��P@��@A��LA��P@��@A������P@��@A����������@A��������SAN���������SAN�����TPA�ABQ����������������B�����������B��@�����...(continues)
翻译为:
TUSLWD2.103.47.775.1904.06.40.03AMBRFD4.63.228.935.0043.09.113.0ASDGHU5.226.47.78.3.26...(The same structure)
其 hexdump 为:
00000000 54 55 53 00 41 42 51 00 00 00 00 00 00 00 00 00 |TUS.ABQ.........|
00000010 00 00 00 00 00 00 28 41 00 00 0e 42 00 00 f8 41 |......(A...B...A|
00000020 00 00 00 00 4c 41 53 00 00 00 00 00 00 00 00 00 |....LAS.........|
00000030 00 00 00 00 00 00 88 41 00 00 26 42 9a 99 11 42 |.......A..&B...B|
(Continues...)
结构是,总是 2 个单词,每个单词 3 个字符(即 TUS 和 LWD)后跟 7 个浮点数,然后它再次重复直到文件结束。
关键是:我只想读取每个字段,如 'TUS'、'LWD'、'2.10'、'3.4'、'7.77'...
而且我只能使用“fread()”来实现!现在,我正在尝试这个:
aux2 = 0;
fseek(fp, SEEK_SET, 0);
fileSize = 0;
while (!feof(fp) && aux<=2) {
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
fread(buffer, sizeof(char)*4, 1, fp);
printf("%s", buffer);
for(i=0; i<7; i++){
fread(&delay, sizeof(float), 1, fp);
printf("%f", delay);
}
printf("\n");
aux++;
fseek(fp,sizeof(char)*7+sizeof(float)*7,SEEK_SET);
aux2+=36;
}
我得到了这个结果:
TUSABQ0.0000000.0000000.00000010.5000000.0000000.00000010.500000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
AB0.0000000.000000-10384675421112248092159136000638976.0000000.0000000.000000-10384675421112248092159136000638976.0000000.000000
但它不能正常工作...
*注意:忘记最后'fseek()'的参数,因为我已经尝试了太多没有意义的事情! 要将单词(即 TUS)写入文件,我使用:
fwrite(x->data->key, 4, sizeof(char), fp);
为了写浮点数,这个:
for (i = 0; i < 7; i++) {
fwrite(¤t->data->retrasos[i], sizeof(float), sizeof(float), fp);
}
我建议使用一个结构来保存每个数据单元:
typedef struct {
float value[7];
char word1[5]; /* 4 + '[=10=]' */
char word2[5]; /* 4 + '[=10=]' */
} unit;
为了使文件格式可移植,您需要一个函数来打包和解包上述结构 to/from 一个 36 字节的数组。在 Intel 和 AMD 架构上,float
对应于 IEEE-754-2008 binary32 格式的小端字节序。例如,
#define STORAGE_UNIT (4+4+7*4)
#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
size_t unit_pack(char *target, const size_t target_len, const unit *source)
{
size_t i;
if (!target || target_len < STORAGE_UNIT || !source) {
errno = EINVAL;
return 0;
}
memcpy(target + 0, source->word1, 4);
memcpy(target + 4, source->word2, 4);
for (i = 0; i < 7; i++)
memcpy(target + 8 + 4*i, &(source->value[i]), 4);
return STORAGE_UNIT;
}
size_t unit_unpack(unit *target, const char *source, const size_t source_len)
{
size_t i;
if (!target || !source || source_len < STORAGE_UNIT) {
errno = EINVAL;
return 0;
}
memcpy(target->word1, source, 4);
target->word1[4] = '[=11=]';
memcpy(target->word2, source + 4, 4);
target->word2[4] = '[=11=]';
for (i = 0; i < 7; i++)
memcpy(&(target->value[i]), source + 8 + i*4, 4);
return STORAGE_UNIT;
}
#else
#error Unsupported architecture!
#endif
以上仅适用于 Intel 和 AMD 机器,但如果需要,很容易扩展到其他架构。 (目前几乎所有机器都使用 IEEE 754-2008 binary32 float
,只是字节顺序有所不同。那些不使用的机器通常有 C 扩展来转换 to/from 它们的内部格式。)
使用上面的方法,你可以——应该!必须! -- 记录你的文件格式,例如如下:
Words are 4 bytes encoded in UTF-8
Floats are IEEE 754-2008 binary32 values in little-endian byte order
A file contains one or more units. Each unit comprises of
Name Description
word1 First word
word2 Second word
value0 First float
value1 Second float
value2 Third float
value3 Fourth float
value4 Fifth float
value5 Sixth float
value6 Second float
There is no padding.
要写一个单元,使用大小为STORAGE_UNIT
的char
数组作为缓存,然后写那个。因此,如果您有 unit *one
,您可以使用
FILE *out
char buffer[STORAGE_UNIT];
if (unit_pack(buffer, sizeof buffer, one)) {
/* Error! Abort program! */
}
if (fwrite(buffer, STORAGE_UNIT, 1, out) != 1) {
/* Write error! Abort program! */
}
相应地,从 FILE *in
读取将是
char buffer[STORAGE_UNIT];
if (fread(buffer, STORAGE_UNIT, 1, in) != 1) {
/* End of file, or read error.
Check feof(in) or/and ferror(in). */
}
if (unit_unpack(one, buffer, STORAGE_UNIT)) {
/* Error! Abort program! */
}
如果 one
是 unit
的数组,并且您正在写入或读取 one[k]
,请改用 &(one[k])
(或等效的 one + k
) one
.