如何使用C中的'fread'从文件中读取和获取分离的数据?

问题描述:

我已经写在一个文件中(使用 '的fwrite()')以下:如何使用C中的'fread'从文件中读取和获取分离的数据?

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��[email protected]������LA��[email protected]��@A��LA��[email protected]��@A������[email protected]��@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(&current->data->retrasos[i], sizeof(float), sizeof(float), fp); 
} 
+0

“* 3个字符的单词*”:为什么...... * 4 ...'。它应该是'fread(缓冲区,sizeof(char)* 3 ...'或者甚至更好的'fread(buffer,sizeof(char),3,...' – alk

+0

cos当我将它们存储在文件中时,每个有一个结尾的'\ 0'字符,所以我试图读回来@alk – wj127

+0

从你显示的转储('TUSABQ ...')它看起来好像末尾的'\ 0'没有被写入或者向我们展示一个* clean *十六进制转储文件,通过一个合适的转储工具(如'hexdump')生成。 – alk

我推荐使用的结构来保存每个数据单元:

typedef struct { 
    float value[7]; 
    char word1[5]; /* 4 + '\0' */ 
    char word2[5]; /* 4 + '\0' */ 
} unit; 

要使文件格式便携式,需要一个包,并从一个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] = '\0'; 

    memcpy(target->word2, source + 4, 4); 
    target->word2[4] = '\0'; 

    for (i = 0; i < 7; i++) 
     memcpy(&(target->value[i]), source + 8 + i*4, 4); 

    return STORAGE_UNIT; 
} 

#else 
#error Unsupported architecture! 
#endif 

以上仅适用于英特尔和AMD机器,但如果需要,它肯定很容易扩展到其他体系结构。 (几乎所有的机器当前都使用IEEE 754-2008 binary32作为float,只是字节顺序有变化,那些没有的,通常有C扩展名可以转换到/从它们的内部格式转换)。

使用上述可以 - 应该!必须! - 记录您的文件格式,例如,如下所示:

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. 

要写单元,使用char阵列大小STORAGE_UNIT的作为高速缓存,并编写。所以,如果你有unit *one,则可以使用

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! */ 
    } 

如果oneunit秒的阵列写入FILE *out,并且你正在写或读one[k],使用&(one[k])(或等效地one + k)而不是one

+0

是的,它的工作!我花了一段时间才明白它,但最终我明白了!非常感谢 !! – wj127

+0

@ wj127:很高兴听到!是的,我......过于冗长;文本墙和所有..顺便说一句,有一个额外的原因,为什么使用这种缓冲区是一个好主意,这是*对齐要求*。根据硬件体系结构的不同,像float这样的特定类型不能只驻留在任何*地址,而是要求地址是一个小数的倍数,以便处理器可以正确访问它。 (或者,未对齐的访问可能会非常缓慢。)使用这样的缓冲区可以让您安全地将数据打包成文件格式,而不用担心这种对齐或填充。 –

+0

不,不会的!实际上,我的这个问题与我为'__Operating Systems__'主题所做的实际有关,所以很高兴能够获得关于它的更多免费信息,并且好像你对此事了解很多!再次感谢! :) – wj127