【问题标题】:How do I process a sequential file with two different types of records?如何处理具有两种不同类型记录的顺序文件?
【发布时间】:2016-01-12 11:38:33
【问题描述】:

对于作为 COBOL 课程一部分的作业,我的输入文件是一个名为 BRANCHTOT.SEQ 的顺序文件,其中包含两种类型的记录:

第一个是我所说的标题记录,它说明文件中的记录总数(不包括标题记录本身)。这只是一条记录。

如果这是文件中唯一的记录,我将其定义如下:

01 header-record.
   03 record-count  PIC 9(6).
   03 FILLER        PIC X(13). 

第二种类型的记录是我必须为输出读取和处理的记录。其结构如下:

01 sales-record.
   03 branch-nr    PIC X(5).
   03 office-nr    PIC 9(2).
   03 count        PIC 9(5).
   03 sum          PIC 9(5)V99.
  1. 如何在 FILE SECTION 和 WORKING-STORAGE SECTION 中定义 BRANCHTOT.SEQ 文件?我是否使用重新定义?

我习惯于处理具有一种记录类型的文件。

  1. 如何在不妨碍标题记录的情况下读取和处理销售记录类型的记录?

任务比我在这里描述的要复杂得多,但是 对于这部分问题,我的程序必须读取和处理销售记录记录并打印它已读取的这些记录的总量,并将其与标题记录中列出的数量进行比较。如果两者不匹配,我需要在我的输出列表中有一个语句来记录这个错误。

  1. 我该怎么做?

【问题讨论】:

  • 通常是这样的问题,答案是:遵循您网站的标准。有很多方法可以做,都是合法的,但只有一种遵循您的网站标准/习惯。他们肯定有例子。重用和适应。
  • 不是针对网站,而是针对课程。这是我被分配的任务之一,而讲师无法提供帮助。我的问题是我不知道很多方法可以做到这一点,所以如果你能向我解释一个,我也许能够弄清楚如何解决这个问题。我不是要找人为我编写程序,而是要推动我走向正确的方向。或者只是一个方向

标签: cobol


【解决方案1】:

您定义了两个记录,您可以完全按照您所显示的那样,在一个 FD 下进行。这会给你一个隐含的 REDEFINES。

在文件的 SELECT 语句中使用 FILE STATUS(总是)。始终检查文件状态字段是否获得预期值。使用 88 条件名称作为“10”值来标识文件结尾。不要使用AT END/NOT AT END

请注意,您的练习不能完美地完成此操作,因为该文件尚未正确定义。没有可用于标识标题记录或数据记录的指示。唯一的指示是“头在前,其余都是数据”。这可能看起来不错,但是当有人腌制最初编写文件的程序时就会变得懒惰,并且没有给你任何标题,或者两个或更多标题。

如果文件具有结构,则该结构应该在数据中,因为它可以被检查。像处理好文件一样处理坏文件可能会非常昂贵。而且很尴尬。

您还需要知道文件是否允许为“空”。由于它有一个标题记录,一个“空”文件应该包含一个数据记录计数为零的标题记录。您的情况可能会有所不同,因为该文件不是经过设计的。

在您的初始处理中(在您的输入文件为OPENed 之后),您读取了第一条记录。如果是这样,请处理“空文件”。检查它是一个标题。存储记录数。

然后您阅读下一条记录。你检查它是 not 一个标题。

然后你处理你的数据,记住你有第一个可用的数据记录。

Loop until end-of-input
  process record
  read next record
End-Loop

在文件末尾(循环结束时),您检查标题上的记录数(从存储的值)到您读取的数据记录数(在记录处理中计算)。

一旦你有了你的程序,你就有了一个“模型”来作为其他程序的基础。您只需将“这就是我处理文件的方式”正确一次,然后将其用作下一个文件处理程序的起点。下一个程序会更复杂,所以你最终会得到另一个模型。

一段时间后,您将拥有大约五个模型,每个模型都基于来自更简单任务的工作代码。

我反对使用AT END/NOT AT END 读取文件有几个原因:

复杂性和可理解性

a-pargraph-for-SO-formatting.
   PERFORM priming-read
   PERFORM 
     UNTIL end-of-infile
       PERFORM process-data
       PEFORM read-next
   END-PERFORM
   .
priming-read.
   PERFORM read-next
   .
read-next.
   READ IN-FILE
   IF NOT IN-FILE-STATUS-OK
       PERFORM diagnostic-message-and-fail
   END-IF
   .

对比

  PERFORM UNTIL WS-EOF='Y'
     READ STUDENT INTO WS-STUDENT
        AT END MOVE 'Y' TO WS-EOF
        NOT AT END DISPLAY WS-STUDENT
     END-READ
  END-PERFORM

您不能在未测试 WS-EOF 的情况下在 END-READ 之后放置任何代码。然而人们会这样做。

可靠性和操作简便性

如果在 SELECT 中为文件指定了 FILE STATUS,则由程序员对其进行测试。如果出现问题,显然 AT END 不正确,但没有新记录。随后的 READ 将得到相同的情况,并且随之而来的是 Big Fat Loop。所以应该测试文件状态字段(如果使用文件状态),那么为什么不使用文件状态字段来测试文件结束,因为它更简单,而不是进一步的条件没有结束。

当然,如果你不使用 FILE STATUS,运行时会处理一些事情,但是以一种广泛而直接的方式,没有机会提供额外的诊断信息,

当然,您也可以使用 USE AFTER... 但这会更加复杂,因为有些东西很多人不习惯。

它鼓励使用 GO TO 来“摆脱困境”

READ IN-FILE
  AT END GO TO no-more-records
END-READ

为什么要在FD下定义记录,为什么不在WORKING-STORAGE中

或者,READ ...READ ... INTO ... 有什么区别?

FILE SECTION 中的FD 允许描述“记录区”中的记录。

对于输入文件,这将是成功读取的最后一条记录。如果有的话。文件的打开将使记录区域可用。一旦遇到文件结尾,将不再有当前记录。文件关闭时也不会有当前记录(无论是否到达文件结尾)。

这意味着您不应该在文件打开之前、关闭之后或到达文件结尾之后访问记录区域。在 IBM 大型机上不应该经常不能,因为它很容易导致S0C4 异常结束,即保护异常。输入区域实际上是在处理文件的 IO 例程中定义的,而不是在您的 COBOL 程序中。 FD 只是将您的定义映射到记录区域的地址。如果当时记录区不存在,则无法访问。

对于一个简单的文件结构,您不需要同时访问来自不同记录的数据,您始终可以使用 FD。

对于更复杂的结构,您需要存储来自不同记录类型的数据,因为FD下只有当前记录可用。

您可以存储整个记录,也可以只存储您需要的部分。

您可以在 READ 之后的某个时间点使用 MOVE 为各个字段存储您需要的部分。

您可以在 READ 之后通过 FD 下的整个记录​​的 MOVE 存储整个记录,或者使用 READ ... INTO ... 自动执行此操作。

READ ... INTO ... 对输入文件中的每条记录执行 MOVE(隐式)。如果您不需要它,那就是浪费资源,而且由于人们为大型机上的资源(如使用的 CPU)付费,因此除非您迫切需要,否则值得避免。

网站通常有当地标准。你遵循标准,即使它们不好(你试图改变它们,并不总是成功)。如果你被告知使用 READ ... INTO ... 你就使用它。

但是,作为参考,我不使用 READ ... INTO ...(除非在上述情况下),并且在使用 FD 和移动我想要的数据(单个字段或整个记录)。

使用 FD 是“最好的”。除非当地标准另有规定。那么按照当地的标准是“最好的”。

请注意,有些东西会修改上述内容并为您的程序中的记录创建特定区域。如果 INTO(以及 WRITE 上的 FROM)可以让您的整个记录​​被隐式移动两次。

【讨论】:

  • 出于好奇:为什么“不要使用 AT END/NOT AT END。”
  • 非常感谢您的详尽回复和补充信息!为了解决 EOF 的情况,我通常使用 88 级,我也想出了自己的小 Abend 例程。我要看看你和 gazzz0x2z 给我的信息能走多远:-D
  • 不过,我还有一个问题:为什么要从 FD 工作?我通常做的是将我定义的结构放在 WS 中。我将输入读入工作存储,所以我可以从那里处理它。我的导师说这是最好的方法,但他的解释到目前为止还很模糊,所以我很好奇你的想法。无论如何,我非常感谢你们两个到目前为止给我的帮助。
  • 没问题。只是一个关于该网站如何运作的提示。如果您稍后有问题,请将其作为新问题提出。您认为最有帮助的答案,您可以考虑“接受”(点击答案旁边的勾号)。当您接受答案时,您将获得两个声望点。
  • 谢谢!也感谢您解释该网站的运作方式。
【解决方案2】:

好的,感谢您的评论,这是一个课程,所以它在风格方面相当免费。 Here is an excellent beginning for reading a file

通常,如果您谈到“重新定义”,则意味着您的老师希望您使用一个。因此,您的记录将被定义为:

01  my-record.
    05  my-header.
        10  record-count  PIC 9(6).
        10  FILLER        PIC X(13).
    05  my-sales-record redefines my-header.
        10 branch-nr    PIC X(5).
        10 office-nr    PIC 9(2).
        10 count        PIC 9(5).
        10 sum          PIC 9(5)V99.

它有效,因为两者都是 19 个字符长。不需要额外的填充物或复杂的东西。

然后,稍后,您将拥有一个

READ myfile INTO my-record

使用计数器(我希望您知道如何使用简单的数字变量)来计算记录。并用它来知道它是否是标题:

IF current-record = 1
    (do something with the header)
ELSE
    (do something with the sales record)
END-IF

确保所有这些都嵌入到我的示例链接中描述的循环中,并且它应该可以工作。

【讨论】:

  • 非常感谢您回复我并尝试帮助我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-14
  • 2012-08-31
  • 1970-01-01
相关资源
最近更新 更多