fscanf在返回之前读取空格分隔的数据

fscanf在返回之前读取空格分隔的数据,c,delimiter,scanf,eol,C,Delimiter,Scanf,Eol,我试图从txt文件中读取数据。txt文件有多个条目,每个条目占用一个新行,每个条目都有由一些符号分隔的可变长度的十六进制字节数据(如空格“”)。示例txt文件如下所示 e4 e2 e2 e1 ff\n f2 a2 22 34\n ff ee dd\n 在循环中使用scanf(fp,“%2x”,buffer+offset),我试图将每个字节加载到字节缓冲区中,直到每行结束,标记一条完整的记录。主要问题是检测换行符,因为scanf完全忽略它并跳转到下一行。我的原始代码是 do{ count

我试图从txt文件中读取数据。txt文件有多个条目,每个条目占用一个新行,每个条目都有由一些符号分隔的可变长度的十六进制字节数据(如空格“”)。示例txt文件如下所示

e4 e2 e2 e1 ff\n
f2 a2 22 34\n
ff ee dd\n
在循环中使用scanf(fp,“%2x”,buffer+offset),我试图将每个字节加载到字节缓冲区中,直到每行结束,标记一条完整的记录。主要问题是检测换行符,因为scanf完全忽略它并跳转到下一行。我的原始代码是

do{
    counter=fscanf(datain,"%2x",buffer1+offset);
    fprintf(stdout,"%#2x ",buffer1[offset]);
    offset+=counter;
}while(!feof(datain));

通过在每个十六进制说明符后添加%c,我可以从流中提取空格和换行符。通过对这个角色的测试,我可以知道一条新线已经到达

do{
    counter=fscanf(datain,"%2x%c",buffer1+offset,&followsymbol);
    fprintf(stdout,"Counter:%i\n",counter);
    if (counter==2)
         {fprintf(stdout,"data:%5x\tfollowsymbol:%5x\n",buffer1[offset],followsymbol);
          offset+=1;
         }
    if(followsymbol==0x0a && counter==2)
          printf("a nl symbol has been detected\n");
}while(!feof(datain));
来自终端的输出

Counter:2
data:ffffffe4   followsymbol:   20
Counter:2
data:ffffffe2   followsymbol:   20
Counter:2
data:ffffffe2   followsymbol:   20
Counter:2
data:ffffffe1   followsymbol:   20
Counter:2
data:ffffffff   followsymbol:    a
a nl symbol has been detected
Counter:2
data:fffffff2   followsymbol:   20
Counter:2
data:ffffffa2   followsymbol:   20
Counter:2
data:   22      followsymbol:   20
Counter:2
data:   34      followsymbol:    a
a nl symbol has been detected
Counter:2
data:ffffffff   followsymbol:   20
Counter:2
data:ffffffee   followsymbol:   20
Counter:2
data:ffffffdd   followsymbol:    a
a nl symbol has been detected
Counter:65535

另一种通常更简单的方法是使用或读取整行,然后使用或处理行上的符号。在许多方面,这与当前方案类似,但您需要能够遍历字符串,因此
%n
转换规范在这里通常很有用:

while (fgets(line, sizeof(line), datain) != 0)
{
    int line_offset = 0;
    int new_offset;
    while (sscanf(line + line_offset, "%2x%n", &buffer1[offset], &new_offset) == 1)
    {
        printf("%#.2x ", buffer1[offset]);
        offset++;
        line_offset += new_offset;
    }
}
%n
转换不计入从
sscanf()
返回的值

请注意,这避免了在另一个示例中看到的一些其他问题。它不会在没有行可读取时尝试处理数据,也不会在没有行可读取时尝试处理数据


此外,一次读取一行的优点之一是,如果您可以给出错误发生的整个上下文(行),而不是在一些不确定的成功转换次数后仍停留在行的剩余部分,则错误报告通常更容易/更好。如果行的第六个字段中有错误字符,您可以简单地显示前五个字段以及错误所在的位置。

为什么要硬编码0x0a,最好使用
\n
替换?需要
如果(计数器==2&&followsymbol==0x0a)
。否则,
followsymbol
可能是先前的值,如果
计数器的值为EOF或1,则应非常小心在转换失败时打印“新到达数据”的代码。同样,对使用
feof()
检测EOF的代码非常谨慎;这几乎总是错误的。请特别注意,当成功读取文件中的最后一个数字时,
feof()
不会显示EOF。有一个完整的问题你应该读一下。使用
do{…}while(!feof(file))不是改进。输出与代码/输入文件不匹配。1)文件的最后一行中没有
\n
,或者2)发布的输出不显示最后一行“检测到新行”之后的内容。feof(datain)
直到在
counter=fscanf()
返回2以外的值之后才会变为真。在每次
fscnaf()
之后尝试打印
counter
,查看。
feof(datain)
在读取最后一个
char
后不会立即返回true。相反,在尝试读取最后一个
char
之后,它返回true。使用来自
fgets()
fgetc()
fscanf()
的返回值比使用
feof()
确定何时停止更好。在接收到失败的读取后,使用
feof()
,确定失败是EOF还是IO错误。