【问题标题】:fscanf reading in space delimited data until returnfscanf 读取空格分隔的数据直到返回
【发布时间】:2014-02-26 18:06:59
【问题描述】:

我试图从 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 delimiter scanf eol


    【解决方案1】:

    完成此类工作的另一种通常更简单的方法是使用fgets()getline() 读取整行,然后使用sscanf() 处理行上的符号。在很多方面,这与当前的方案类似,但您需要能够通过字符串进行,因此%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() 的回报。

    请注意,这避免了另一个answer 中出现的一些其他问题。当没有一行要读取时,它不会尝试处理数据,当没有任何剩余时,它不会尝试处理数据。

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

    【讨论】:

      【解决方案2】:

      通过在每个十六进制说明符后附加一个 %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
      

      【讨论】:

      • 为什么要硬编码 0x0a,使用 \n 可能会更好?
      • 需要if(counter==2 && followsymbol==0x0a)。否则,followsymbol 可能是之前的值,counter 的值应为 EOF 或 1。
      • 当实际上转换失败时,要对打印“新到达的数据”的代码非常谨慎。同样非常警惕使用feof() 检测EOF 的代码;这几乎总是错误的。请特别注意,当文件中的最后一个数字被成功读取时,feof() 不会说 EOF。 while (!feof(file)) is always wrong 上有一个完整的问题,您应该阅读。使用do { … } while (!feof(file)); 并不是一种改进。
      • 输出与代码/输入文件不匹配。要么 1) 文件的最后一行中没有 \n,要么 2) 发布的输出未显示最后一个“检测到新行”之后的内容。 feof(datain) 直到 after counter=fscanf() 返回 2 以外的值后才会变为 true。尝试在每个 fscnaf() 之后打印 counter 以查看。
      • feof(datain) 在最后一个 char 被读取后是否 not 返回 true。相反,它尝试读取过去最后一个char后返回true。使用来自fgets()fgetc()fscanf() 的返回值是比使用feof() 确定何时停止更好的方法。使用feof()接收到失败的读取来确定失败是EOF还是IO错误。
      猜你喜欢
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 2022-07-30
      • 1970-01-01
      相关资源
      最近更新 更多