【问题标题】:Data conversion from a .DAT file generated from COBOL从 COBOL 生成的 .DAT 文件进行数据转换
【发布时间】:2011-02-16 16:01:45
【问题描述】:

我正在尝试从 COBOL 程序生成的 .DAT 文件中获取值。 但问题是当我尝试将数据显示到我的 c++ 程序时。 我得到一个奇怪的值,比如 15.25 我得到 960000。

我的问题是: 导入的首选数据类型是什么

PIC  S9999V99  COMP-5  VALUE +0

and

PIC  S9(7)     COMP-5  VALUE +0

我的 c++ 代码将字节导入 long

BOOL Import( LONG &nVal, INT nNumChars, FILE *pFile )
{
   char strVal[10];

   for ( int n = 0; n < (nNumChars); n++ )
   {
      if ( fread( &strVal[n], 1, 1, pFile ) != 1 )
      {
         return FALSE;
      }
   }

   strVal[n] = NULL;

   nVal = atol(strVal);

   return TRUE;
}

第一条记录的十六进制

30 31 34 38 35 37 42 E7    03 00 00 00 00 00 00 31
32 2F 34 32 20 20 31 30    30 30 30 20 20 20 20 20
20 20 20 20 20 20 20 20

【问题讨论】:

  • Comp-5 是一种机器相关格式。在回答之前,我想在您的问题中查看完整记录的十六进制转储。
  • 只需写下一条记录的十六进制转储。没有这个,任何人都无法正确回答
  • 您似乎期待数字的文本格式。 COBOL 确实使用了这些(或者在我使用它时确实使用过),但也使用了其他几种格式。 COMP-5 似乎是标准的二进制数据,因此请尝试将其读取为常规的四字节整数。请记住,小数点通常是隐含的,在编译器保留小数点的情况下,15.25 可能是 1525。
  • 你知道第一张唱片应该产生什么吗?它看起来像 ASCII 它是“014857B?2/42 10 ???????1000”在哪里?超出标准的 96 个 ASCII 可打印字符。没有 1525 的迹象。这确实表明它使用的是文本格式,但您没有正确找到数字的结尾。
  • @RyanA 请张贴COBOL程序的FD记录。文件中的数据不是您所描述的,但可能是有效的 ASCII 和另一种 FD 格式的二进制数据。

标签: c++ cobol


【解决方案1】:

这是您要阅读的记录:

  0  1  4  8  5  7  B --    -- -- --  z e r o e s 1    2  / 4  2   b  b  1  0

 30 31 34 38 35 37 42 E7    03 00 00 00 00 00 00 31   32 2F 34 32 20 20 31 30 
 ///////////////////////////////////////////////////////////////////////////////    
  0  0  0  b  b  b  b  b     b  b  b  b  b  b  b  b  

 30 30 30 20 20 20 20 20    20 20 20 20 20 20 20 20 

在哪里

b means whitespace  

zeroes are binary zeros

-- is a BINARY NUMBER COMP-5 and reversed (000003E7) == 999

因此,您的 1525 没有任何痕迹,但也许这可以帮助您识别内容。 看那个“999”!

HTH!

【讨论】:

  • 我和你一起赌这个。但是,在没有原始记录布局的情况下解码数据时,我们总是充满信心。其中一些类似 alpha 的字符序列也可能是二进制数,只是偶然地也映射到 ascii 字符(最好查看几条记录)。 OP 应该注意的另一件事是 COBOL 应用程序经常使用多重定义的记录布局,因此来自同一文件的不同记录可能具有不同的记录布局。
  • @NealB 当然,回答部分信息总是有风险的。这是一半猜测,但这是我提供的信息的最佳猜测。尝试连接两个完全不同的系统在几年前曾经是一项常见的任务,但随着几代程序员总是在同构配置或仅使用 DB 工作,似乎有些技巧正在丢失。
【解决方案2】:

您的问题中确实没有足够的信息来回答它。

要做的事情是查看生成数据文件的程序,并复制其中的结构。

【讨论】:

    【解决方案3】:

    正如之前作者所说,需要更多信息;即哪个Cobol 编译器Cobol Copybook(或其中的一部分)会很有用。

    但是以字符数组的形式读入并使用 atol 可能是错误的。

    对于大多数 Cobol 编译器(RM Cobol 不同)你会

    • 读取为字节数组
    • 从字节数组计算。对于 2 字节的正数,您可以

      long val = byte_array[0] * 256 + byte_array[1] /* 大结局 */ long val = byte_array[0] + byte_array[1] * 256 /* 小结尾 */

    注意: * 256 应该移位 8 位,但我不记得 C 移位运算符


    Pic 99V99 中的 V 是假定的小数位,即 您需要将以下计算添加到代码中

     double ret_val = long_val / 10      /* if  pic p(?)V9 */
     double ret_val = long_val / 100     /* if  pic p(?)V99 */
     double ret_val = long_val / 1000    /* if  pic p(?)V999 */
     double ret_val = long_val / 10000   /* if  pic p(?)V9990 */
    

    获得真正的价值。

    注意:有些编辑器可以使用 Cobol 显示 Cobol 数据文件 Copybook(取决于 Cobol 的哪个版本)。

    【讨论】:

      【解决方案4】:

      PIC S9(7) COMP-5 VALUE +0

      COMP-5 表示该值以二进制形式存储。 (您可能需要交换字节,具体取决于平台。)S 表示该字段已签名(可能是二进制补码)。 9(7) 表示该字段必须为高达 ±9999999 的值留出空间,这需要 4 个字节(1 个符号位 + 24 个值位 + 7 个填充位)。所以等价的C数据类型是int32_t

      PIC S9999V99 COMP-5 VALUE +0

      V 是一个隐含的小数位。 COBOL 程序放入其中的任何内容都会在后台缩放 100(例如,15.25 存储为 001525,16 存储为 001600,等等)。在 C++ 中,您必须自己进行缩放。

      我通常将double 用于外部数据类型,但小数点后两位强烈建议使用美元和美分,如果有可用的小数类型,则应使用十进制类型。

      30 31 34 38 35 37 42 E7    03 00 00 00 00 00 00 31
      32 2F 34 32 20 20 31 30    30 30 30 20 20 20 20 20
      20 20 20 20 20 20 20 20
      

      这看起来像 ASCII 字符串 014857B�␃␀␀␀␀␀␀12/42 10000,它会建议 DISPLAY 而不是 COMP-5 数字。您确定您查看的是记录的正确部分吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-01
        • 1970-01-01
        • 2014-08-25
        • 2015-06-27
        • 2020-11-03
        • 1970-01-01
        • 2012-02-23
        相关资源
        最近更新 更多