我是COBOL的新手,无法搜索.dat文件中的特定条目。 我们的想法是在文件中搜索其中一个字段中具有特定代码的所有记录。
我试图在谷歌找到答案,但我到处都回答不同,我不知道为什么我不能适应我的问题。
我也发现了这个问题:
但答案并没有详细说明。
这是我的代码:
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.
编辑 - 我更改了代码,所以我会在这里发布新代码:
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
TITULO:测试
DESCRICAO:说明
ID-ATUALIZACAO:0000000002
COD-RASTREIO:qweqweqweqweqwee
TITULO:test2
DESCRICAO:description2
答案 0 :(得分:2)
因为SELECT中有ACCESS RANDOM
,READ file-name
(没有NEXT或KEY)的默认操作是键控读取。
将其更改为ACCESS SEQUENTIAL
无论如何,将其更改为READ file-name NEXT
,这是一个明确的顺序读取。
我总是在READ上使用显式的NEXT或KEY,以便不依赖于默认行为,这取决于文件的类型(以及OPEN的类型)。
我忘记明确的时候就是当我复制其他人的例子而不够小心的时候,我很抱歉我错过了你原本没有NEXT。
因为您没有使用OPEN I-O(您没有使用键控读取或START,所以您不需要ACCESS的RANDOM或DYNAMIC)只需使用OPEN ... INPUT
。
您尚未提及用户输入的要求。用户输入可能/可能不需要处于循环中。
您的OPEN后没有检查文件状态字段。你会发现那里有问题。在同一程序中多次打开同一文件是不好的做法,即使您多次关闭文件(您没有这样做,因此可能存在问题。
好的,首先是READ。好的,先退回到SELECT上的文件状态。
在文件上使用FILE STATUS会获得一个双字节字段,告诉您上次IO操作发生了什么。如果该字段包含零,一切都很好。
我建议您对可能使用的所有文件使用FILE STATUS,并在文件上的每个IO之后检查文件状态字段(每个文件保持唯一)。
对文件使用文件状态告诉COBOL运行时"我将处理出现的任何问题,通过在此字段中输入代码告诉我何时出现问题&#34 34。
如果您使用文件状态而不要检查文件状态字段,则IO错误会悄然消失。
现在回到READ。
这将读取下一个可用记录。
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:
PERFORM READ-input-file
PERFORM
UNTIL end-of-input-file
PERFORM process-input
PERFORM READ-input-file
END-PERFORM
然后READ-input-file可以检查文件状态字段(88级),而不会使代码混乱。
进一步改善。你有两个PERFORMs" read",但它们不一样,所以给它们命名不同:
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
.
然后你有一个简单的通用程序,它在一个循环中读取一个文件直到文件结束,你可以在任何需要的时候用它作为基础。
您可以轻松地沿着相同的行扩展代码以处理"文件标题"在一个文件上,然后进行一些更改以处理"文件预告片",确保每个只有一个,标题是第一个,预告片是最后一个,标题是正确的文件和正确的营业日期和预告片具有正确的记录计数和哈希总数。
所有这些都不会干扰程序的控制逻辑。
然后你有第二个程序,你也可以用作基础。
对于您的任务,您首先需要与用户交互,存储用户数据,针对每条记录测试数据。这可能是用户输入的一个,或几个,你没有说。
如果用户的输入取决于已显示的结果,则只需存储文件中的记录。可能就是这种情况,你没有说。
如果用户提供一条输入以匹配一个字段,则只需在处理每条记录时测试该值(已获取)。
原始程序出现问题:
在SELECT上使用的文件状态但没有检查文件状态字段(ST-ATUALIZACAO)。
文件的第二个OPEN,它将在300-STORE-NAME中失败(文件已经打开)。
300-STORE-NAME中文件的关闭。哪个会奏效。但现在当您执行下一次READ时,您的文件将被关闭。所以READ不会起作用。它是如何运作的(如果它会做什么)?好吧,我想,因为我不知道,因为我没有这样编码,那就是阅读指定了FILE STATUS的关闭文件和AT END将导致AT END被处理。肯定FD下01级的内容是不确定的。
每次向表格添加记录时,您都试图搜索表格。如果你需要将所有记录存储在一个表中,只有在你有文件结束并且所有内容都在表格中时才进行搜索。
一旦有了工作程序,就会有另一个名为Code Review的StackExchange站点,您可以在其中询问如何更好地编写代码。
创建一个非常简单的程序,它在循环中读取输入文件,直到文件结束。
在该程序开始时,获取用户输入。如果有多个用户输入,请将其存储在带有OCCURS的表中。
对于每个读取的记录,请检查用户数据(单个字段或表格),并在得到匹配项时生成输出。
在这里查看答案Cobol Read statement format. Can it be redone a different way?,然后点击链接。注意如何使用启动读取,以及如何使用文件状态字段来实际检查错误并在顺序读取文件时识别文件的结尾。