使用 COBOL 从 .dat 文件中获取特定条目

Get specific entries from .dat file with COBOL

我是 COBOL 新手,在 .dat 文件中搜索特定条目时遇到问题。 这个想法是在文件中搜索在其中一个字段中具有特定代码的所有记录。

我试图在 google 中找到答案,但无论我走到哪里,答案都是不同的,我不知道为什么我不能使它们适应我的问题。

我也发现了这个问题:

How to insert records in a table in a text file using COBOL and search and display record(s) which satisfy a condition?

但答案不详

这是我的代码:

IDENTIFICATION DIVISION.
   program-id. AR AS "A.AR".

   environment division.
   configuration section.
   special-names.  DECIMAL-POINT   IS  COMMA.
   INPUT-OUTPUT    SECTION.
   FILE-CONTROL.
       SELECT  ARQ-ATUALIZACAO  ASSIGN  "C:\temp\atualizacao.dat"
       ORGANIZATION    IS  INDEXED
       ACCESS  MODE    IS  SEQUENTIAL
       RECORD  KEY     IS ID-ATUALIZACAO
       ALTERNATE RECORD KEY IS COD-RASTREIO
       FILE    STATUS  IS  ST-ATUALIZACAO.

   data division.
   FILE    SECTION.
   FD  ARQ-ATUALIZACAO.
   01  REG-ATUALIZACAO.
       05  ID-ATUALIZACAO  PIC 9(10).
       05  COD-RASTREIO    PIC X(13).
       05  TITULO          PIC X(15).
       05  DESCRICAO       PIC X(30).
       05  FILLER          PIC X(30).
   working-storage section.
   01 WS-RECORD.
       03 ENTRIES OCCURS 18 TIMES INDEXED BY I.
           05 WS-ID   PIC 9(10).
           05 WS-RAST PIC X(13).
           05 WS-TIT  PIC X(15).
           05 WS-DESC PIC X(30).
   77  ARE-THERE-MORE-RECORDS PIC XXX VALUE "YES".
   77  NAME-COUNT          PIC 99.
   77  PROCURA             PIC X(13).
   77  ST-ATUALIZACAO      PIC XX  VALUE   SPACES.

   procedure division.
   OPEN INPUT ARQ-ATUALIZACAO
       PERFORM UNTIL ARE-THERE-MORE-RECORDS = 'NO '
           READ ARQ-ATUALIZACAO
               AT END
                   MOVE 'NO ' TO ARE-THERE-MORE-RECORDS
               NOT AT END
                   PERFORM 300-STORE-NAME
           END-READ
       END-PERFORM
   CLOSE ARQ-ATUALIZACAO.

   300-STORE-NAME.
   ADD 1 TO NAME-COUNT
   MOVE REG-ATUALIZACAO TO ENTRIES OF WS-RECORD(NAME-COUNT).

   OPEN    I-O ARQ-ATUALIZACAO

       DISPLAY "CODIGO DA ENCOMENDA.:" AT  1010
       DISPLAY "STATUS:"       AT  2433
       DISPLAY ST-ATUALIZACAO   AT  2440
       ACCEPT  PROCURA    AT 1030 WITH REQUIRED FULL
       SEARCH ENTRIES
           AT END DISPLAY "CODIGO NAO ENCONTRADO" AT 0210
           WHEN  WS-RAST(I) = PROCURA
           DISPLAY "REGISTROS ENCONTRADOS" AT 0210
           DISPLAY WS-RAST(I)  AT 0310
           DISPLAY WS-ID(I)    AT 0410
           DISPLAY WS-TIT(I)   AT 0510
           DISPLAY WS-DESC(I)  AT 0610
       END-SEARCH
   CLOSE ARQ-ATUALIZACAO
   EXIT PROGRAM.

编辑 - 我更改了很多代码,所以我将 post 新代码放在这里:

   IDENTIFICATION DIVISION.
   program-id. ATUALIZACAOR AS "ATUALIZACAO.ATUALIZACAOR".
   environment division.
   configuration section.
   special-names.  DECIMAL-POINT   IS  COMMA.
   INPUT-OUTPUT    SECTION.
   FILE-CONTROL.
       SELECT  ARQ-ATUALIZACAO  ASSIGN  "C:\temp\atualizacao.dat"
       ORGANIZATION    IS  INDEXED
       RECORD  KEY     IS  ID-ATUALIZACAO
       ALTERNATE RECORD KEY IS COD-RASTREIO
       ACCESS  MODE    IS  RANDOM
       FILE    STATUS  IS  ST-ATUALIZACAO.

   data division.
   FILE    SECTION.
   FD  ARQ-ATUALIZACAO.
   01  REG-ATUALIZACAO.
       05  ID-ATUALIZACAO  PIC 9(10).
       05  COD-RASTREIO    PIC X(13).
       05  TITULO          PIC X(15).
       05  DESCRICAO       PIC X(30).
       05  FILLER          PIC X(30).
   working-storage section.
   01  ST-ATUALIZACAO      PIC XX.
       88 end-of-input-file    VALUE   "10".
       88  INPUT-FILE-OK       VALUE ZERO "10".
   77  PROCURA             PIC X(13). 
   77  RESP                PIC X   VALUE   SPACE.

   procedure division.
   INICIO.
       PERFORM WITH    TEST    AFTER   UNTIL   RESP    =   "N"
           DISPLAY "CODIGO DA ENCOMENDA.:" AT  1010 ERASE SCREEN
           DISPLAY "STATUS:"       AT  2433
           DISPLAY ST-ATUALIZACAO   AT  2440
           ACCEPT  PROCURA    AT 1030 WITH REQUIRED FULL
           OPEN I-O ARQ-ATUALIZACAO
           PERFORM                      priming-READ-input-file
               PERFORM
                   UNTIL end-of-input-file
               PERFORM                  process-input
               PERFORM                  READ-input-file
           END-PERFORM
           DISPLAY "DESEJA CONSULTAR OUTRA ATUALIZACAO? (S/N)"   
               AT 2001                                                  
               ACCEPT  RESP        AT  2044    WITH    UPPER
       END-PERFORM
       CLOSE ARQ-ATUALIZACAO
       EXIT PROGRAM
   .

   priming-READ-input-file.
       PERFORM     READ-input-file
       IF end-of-input-file
           DISPLAY "END OF FILE" AT 2510
       END-IF
   .

   READ-input-file.
       READ ARQ-ATUALIZACAO
           IF NOT INPUT-FILE-OK
               DISPLAY "FILE NOT OK" AT 2310
               DISPLAY ST-ATUALIZACAO   AT  2440
               STOP " "
           END-IF
   .

   process-input.
       IF COD-RASTREIO = PROCURA
           DISPLAY ID-ATUALIZACAO AT 2410 
           STOP " "
       END-IF
   .

我在文件 'atualizacao.dat' 中的示例数据是:

ID-ATUALIZACAO: 0000000001
COD-RASTREIO: qweqweqweqweqwee
标题:测试
DESCRICAO: 描述

ID-ATUALIZACAO: 0000000002
COD-RASTREIO: qweqweqweqweqwee
标题:test2
DESCRICAO: 描述2

因为您的 SELECT 中有 ACCESS RANDOMREAD file-name(没有 NEXT 或 KEY)的默认操作是键读。

将其更改为 ACCESS SEQUENTIAL

无论如何将其更改为 READ file-name NEXT,这是一个明确的顺序读取。

我总是在 READ 上使用明确的 NEXT 或 KEY,以免依赖默认行为,这取决于文件类型(和 OPEN 类型)。

我忘记说清楚的时候是我不小心复制了别人的例子,对不起我错过了你原来没有NEXT。

因为您没有使用 OPEN I-O(您没有进行键控读取或启动,所以您不需要 RANDOM 或 DYNAMIC 来访问)只需使用 OPEN ... INPUT.

您没有提到用户输入的要求。 perhaps/probably 用户输入不需要循环。

您没有在打开后检查文件状态字段。你会发现你在那里有问题。在同一个程序中多次打开同一个文件是不好的做法,即使你多次关闭文件(你没有这样做,所以可能会有问题。


好的,首先阅读。好的,先回到 SELECT.

上的文件状态

在一个文件上使用 FILE STATUS 可以得到一个两字节的字段,它告诉您上次 IO 操作发生了什么。如果该字段包含零,则一切都很好。

我建议对您可能使用的所有文件使用文件状态,并在文件上的每个 IO 之后检查文件状态字段(使每个文件保持唯一)。

使用文件的文件状态告诉 COBOL 运行-time "I'm going to deal with any problems that arise, you tell me when there was a problem by putting a code in this field".

如果您使用文件状态并且检查文件状态字段,IO 错误会悄悄消失。

现在回到阅读。

这将读取下一条可用记录。

READ file-name

如果遇到文件结尾,文件状态字段将设置为“10”。

您可以为文件状态字段定义 88 级条件名称:

01  input-file-status                   PIC XX.
    88  end-of-input-file               VALUE "10".

你的循环可以是:

PERFORM
  UNTIL end-of-input-file
    READ input-file
END-PERFORM

仅仅读取文件没有多大用处,您还想处理数据。使代码更复杂的一种方法是在 READ 和 PERFORM 之后测试输入文件结尾,如果不是:

PERFORM
  UNTIL end-of-input-file
    READ input-file
    IF NOT end-of-input-file
        PERFORM process-input
    END-IF
END-PERFORM

将其与 "priming read" 进行比较,这意味着您在开始循环之前读取了第一条记录(如果存在):

READ input-file
PERFORM
  UNTIL end-of-input-file
    PERFORM process-input
    READ input-file
END-PERFORM

每次执行 PERFORM 时,要么有一个记录可供处理,要么在上一个 PERFORM 的末尾标识了文件末尾。

将它与您拥有的东西进行比较:

PERFORM 
  UNTIL ARE-THERE-MORE-RECORDS = 'NO '
    READ ARQ-ATUALIZACAO
      AT END
         MOVE 'NO ' TO ARE-THERE-MORE-RECORDS
      NOT AT END
         PERFORM 300-STORE-NAME
    END-READ
END-PERFORM        

我说过在每次 IO 后测试文件状态字段。那会让事情看起来很乱,那么如何避免呢?执行:

PERFORM                      READ-input-file
PERFORM
  UNTIL end-of-input-file
    PERFORM                  process-input
    PERFORM                  READ-input-file
END-PERFORM

然后 READ-input-file 可以检查文件状态字段(88 级)而不会使代码混乱。

进一步改进。你有两个 "read" 的 PERFORM,但它们不一样,所以给它们取不同的名字:

PERFORM                      priming-READ-input-file
PERFORM
  UNTIL end-of-input-file
    PERFORM                  process-input
    PERFORM                  READ-input-file
END-PERFORM

然后:

priming-READ-input-file.
    PERFORM                  READ-input-file
    .

现在的代码和以前一样,但讲述了一个更好的故事。并且可以进一步改进,而不复杂化:

priming-READ-input-file.
    PERFORM                  READ-input-file
    IF end-of-input-file
        do something which says "hey, there should always be records,
        a bad thing has happened" and then crash whilst DISPLAYing
        necessary information
    END-IF
    .

然后你就有了一个通用的、简单的程序,它循环读取文件直到文件结束,你可以在任何需要的时候将其用作基础。

您可以轻松地沿着相同的行扩展代码以处理文件上的 "file header",然后进行一些更改以处理 "file trailer",确保每个只有一个,头在前,尾在后,头用于正确的文件和正确的业务日期,尾有正确的记录数和哈希总数。

一切都不会干扰程序的控制逻辑。

然后你有第二个程序,你也可以用作基础。


对于您的任务,您首先需要与用户交互、存储用户数据、针对每条记录测试数据。这可能是一条用户输入,也可能是几条,你没说。

如果用户的输入取决于已经显示的结果,您只需要存储文件中的记录。可能是这样,你没说。

如果用户提供一个输入来匹配一个字段,则在处理每条记录时只需测试该值(已获取)。


你原来的程序有问题:

FILE STATUS 在 SELECT 上使用但未检查文件状态字段 (ST-ATUALIZACAO)。

文件的第二次打开,在 300-STORE-NAME 中将失败(文件已经打开)。

关闭 300-STORE-NAME 中的文件。哪个会起作用。但是现在,当您执行下一次 READ 时,您的文件已关闭。所以 READ 将不起作用。它怎么会不起作用(确切地说它会做什么)?好吧,我认为,因为我不知道,因为我不那样编码 , 对指定文件状态的已关闭文件的 READ 和 AT END 将导致 AT END 被处理。 FD下01级的内容肯定是undefined

每次向 table 添加记录时,您都在尝试搜索 table。如果您 需要 将所有记录存储在 table 中,只有在到达文件末尾并且所有内容都在 [=138= 中时才进行搜索].

一旦你有一个工作程序,还有另一个 StackExchange 站点,称为 Code Review,你可以在那里询问如何使工作代码更好。


制作一个非常简单的程序,循环读取输入文件,直到文件结束。

在该程序开始时,获取用户输入。如果有多个用户输入,将其存储在 table 中,并带有 OCCURS。

对于读取的每条记录,检查用户数据(单个字段,或 table)并在匹配时生成输出。

在这里查看答案,Cobol Read statement format. Can it be redone a different way?,然后关注 link。注意如何使用启动读取,以及如何使用文件状态字段实际检查错误并在顺序读取文件时识别文件结尾。