读取一个由Cobol生成的文件

8
我目前正在编写一个C#应用程序,它将位于两个现有应用程序之间。我所知道的第二个应用程序是处理由第一个应用程序生成的文件。第一个应用程序是用Cobol编写的。
步骤: 1)Cobol应用程序编写一些文件并将其复制到目录中。 2)第二个应用程序拾取这些文件并处理它们。
我的C#应用程序将位于1)和2)之间。它必须拾取1)生成的文件,读取它,修改它并保存它,以便应用程序2)不知道我甚至已经在那里。
我有几个问题。
首先,如果我在记事本中打开由1)生成的文件,大部分内容都无法阅读,而其他部分则可以。
如果我读取文件,修改它并保存,我必须使用与Cobol应用程序相同的标记来保存文件,以便应用程序2)不知道我已经在那里。
我尝试了这种方式读取文件,但它仍然无法阅读:
代码:
        string ss = @"filename";

        using (FileStream fs = new FileStream(ss, FileMode.Open))
        {
            StreamReader sr = new StreamReader(fs);
            string gg = sr.ReadToEnd();
        }

如果我找到了一种使其可读的方法(使用某种编码技术),那么当我再次保存文件时,我担心会改变它的原始格式。

有什么想法?建议?


3
你需要找出COBOL的供应商,然后找出文件格式是什么。没有单一的“COBOL”格式。 - John Saunders
1
@rauland 希望是密码和信用卡详细信息。 :) - Tim Lloyd
嗨,感谢您的建议。两个文件都有虚拟数据,我也已经请求发布这些文件的许可,所以我认为发布它们没有任何问题,如果有人能够帮忙识别文件类型,那就最好了。这些文件有一个名为CDL的头部,记录了“etiquetas”类型的内容,但缺少尾部部分(这是我应该从C#中完成的)。目前,我需要一种方法来计算文件中有多少条记录,因此必须确定文件中的某种分隔符。非常感谢! - Rauland
简单回顾一下文件结构,它以头部开始,然后是数据记录,最后是尾部。通过编辑器检查文件,我认为每个COBOL文件的结构都是这样的:对于每个记录,都有一个结构或类型定义,然后是实际数据。这似乎对文件中的每个记录都是如此。所以回到C#,如果我需要计算这些数据记录,我需要:-打开文件。-检测头部开始和结束的位置。 - Rauland
1
在这里查看更多信息链接 - GilShalit
显示剩余26条评论
3个回答

29

要读取由COBOL生成的文件,您需要知道:

首先,您需要获取该文件的记录布局(副本)。 COBOL记录布局将类似于以下内容:

01  PATIENT-TREATMENTS.
    05  PATIENT-NAME                PIC X(30).
    05  PATIENT-SS-NUMBER           PIC 9(9).
    05  NUMBER-OF-TREATMENTS        PIC 99 COMP-3.
    05  TREATMENT-HISTORY OCCURS 0 TO 50 TIMES
           DEPENDING ON NUMBER-OF-TREATMENTS
           INDEXED BY TREATMENT-POINTER.
        10  TREATMENT-DATE.
            15  TREATMENT-DAY        PIC 99.
            15  TREATMENT-MONTH      PIC 99.
            15  TREATMENT-YEAR       PIC 9(4).
        10  TREATING-PHYSICIAN       PIC X(30).
        10  TREATMENT-CODE           PIC 99.
你还需要一份IBM的《操作原理》副本(S/360、S370、z/OS都可以,对于我们的目的来说没有关系)。最新版本可从IBM获取:http://www-01.ibm.com/support/docview.wss?uid=isg2b9de5f05a9d57819852571c500428f9a(但你需要一个IBM账户),旧版本可免费获取:http://www.hack.org/mc/texts/principles-of-operation.pdf。其中第8章(十进制指令)和第9章(浮点数概述和支持指令)对于我们的目的非常有用。如果没有这些,你可能会感到茫然。然后,你需要了解COBOL数据类型。例如:PIC定义了一个字母数字格式化字段(例如,PIC 9(4)是4个十进制数字,如果缺失可能会填充4个空格字符)。Pic 999V99是5个十进制数字,并有一个隐含的小数点。等等。BINARY通常是带符号的定点二进制整数。通常大小为半字(2个八位字节)和全字(4个八位字节)。COMP-1是单精度浮点数。COMP-2是双精度浮点数。如果数据源是IBM主机,COMP-1和COMP-2可能不会是IEE浮点数:它将是IBM的基于16进制64浮点格式。你需要像S/370操作原理这样的东西来帮助你理解它。COMP-3是“紧缩十进制”,长度不等。紧缩十进制是一种表示十进制数的紧凑方式。声明将看起来像这样:PIC S9999V99 COMP-3。这表示它具有符号,由6个十进制数字组成,并有一个隐含的小数点。压缩的十进制将每个十进制数字表示为八位字节的半字(十六进制值0-9)。高位数字是左侧八位字节的上半字节。右侧八位字节的低半字节是表示符号的十六进制值A-F。因此,以上PIC子句将需要ceil((6+1)/2)或4个八位字节。例如,以上PIC子句表示的值-345.67看起来像0x0034567D。实际的符号值可能有所不同(默认值为C/正数,D/负数,但A、C、E和F被视为正数,而只有B和D被视为负数)。同样,请参阅S\370操作原理以获取有关表示的详细信息。与COMP-3相关的是区域十进制。这可能声明为“PIC S9999V99”(带符号,5个十进制数字,并有一个隐含的小数点)。在EBCDIC中,十进制数字是十六进制值0xFO-0xF9。'Unpack'(主机机器指令)需要一个紧缩的十进制字段并将其转换为字符字段。该过程如下:从最右边的八位字节开始。反转它,使符号半字节置于顶部,并将其放入目标字段的最右侧八位字节中。从右到左工作(源和目标都是),剥离

我明天会回来给你点赞 - 今天已经用完了。非常好的答案。看起来是一个相当艰巨的任务! :) - Tim Lloyd
通常情况并不像看起来的那样糟糕。大多数COBOL应用程序会编写直接字符格式记录。你很少在野外看到浮点数,但你可能会看到压缩十进制或定点二进制。固定点二进制是一种直接的1:1映射到shortint(除了大端/小端问题)。压缩十进制有点麻烦,但编写转换例程来转换为decimal并不那么糟糕。 - Nicholas Carey
不是我的本行 B^)。我已经离开主机世界很久了,尽管最近我确实不得不经历构建一个过程的过程,以定期导入包含文本、二进制和压缩十进制数据混合的 COBOL 文件转换到 .Net/SQL Server 世界中。从 EBCDIC 转换 [大多数情况下] 相当容易,因为 .Net TextInfo 支持几个 EBCDIC 代码页 (例如 037 和 500)。必须编写一个压缩十进制到 decimal 的转换例程,并将固定点从大端转换为小端。简单! - Nicholas Carey
1
除非您指定SYNCHRONIZED,否则主机不会进行对齐操作。 - Bill Woodger

2
  • 要了解您正在处理哪种Cobol方言可能非常有用,因为没有单一的Cobol格式。一些Cobol编译器(Micro Focus)在文件开头放置“文件描述符”(对于Micro Focus VB/Indexed文件)。

  • 看看RecordEditor (http://record-editor.sourceforge.net/)。它有一个文件向导,可以为您提供很大的帮助。

    • 在文件向导中将文件设置为定长文件(Cobol中最常见)。该程序允许您尝试不同的记录长度。当您获得正确的记录长度时,文本字段应该对齐。
    • 在向导的后面有一个字段搜索功能,可以查找二进制、Comp-3和文本字段。
    • 这里有一些关于如何使用RecordEditor的向导处理未知文件的说明。http://record-editor.sourceforge.net/Unkown.htm
  • 除非文件来自Mainframe/AS400,否则不太可能使用EBCDIC(cp037 - 码页37是美国EBCDIC),任何文本都很可能是Ascii。

  • 文件可能包含Packed-Decimal (Comp3)和Binary-Integer数据。大多数Cobol即使在Intel (little endian hardware)上也使用Big-Endian(对于Comp整数)。

  • 记住一件事情,Cobol PIC s9(6)V99 comp存储为二进制整数,x'0001'表示0.01。因此,除非您有Cobol定义,否则无法确定二进制1是1 0.1、0.01等。


2

我从你问题的评论中看到,你正在处理“经典”的COBOL批处理文件结构:头记录、详细记录和尾记录。

如果你负责创建尾记录,那可能是个坏消息!典型的“尾”记录用于标识文件结束,并提供控制信息,如在其之前的记录数量以及各种检查和/或“详细”记录的总计。换句话说,你可能需要阅读并汇总整个文件以创建尾记录。加上文件中的大部分数据可能是Packed Decimal、Zoned Decimal或其他COBOLish数字数据类型,你可能会遇到一些困难。

你可能想问为什么要向这些文件添加尾记录。通常,“尾”是由创建“详细”记录的同一程序或应用程序生成的。尾记录应该作为验证,确保发送应用程序/程序写入了所有它应该写入的数据。汇总总数、计数等信息用于接收应用程序验证详细记录与前面的详细记录相符。这应该作为另一个验证,证明发送应用程序没有弄乱数据,或者数据在传输过程中没有被损坏(这不是一个玩笑,但也许应该是)。当“中间人”创建尾记录时,这有点破坏了整个练习的目的(无论它一开始有多么缺陷)。


+1 提醒我当总字段在尾部溢出时会变得多么糟糕 :) - Dr. belisarius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接