2015-05-25 3 views
1

Я новичок в COBOL и не удалось найти конкретные записи в файле .dat. Идея состоит в том, чтобы искать файл для всех записей, имеющих определенный код в одном из полей.Получить конкретные записи из .dat-файла с помощью COBOL

Я попытался найти ответ в 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. 

Edit - Я изменил код много, поэтому я выложу новый здесь:

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
ХПК-RASTREIO: qweqweqweqweqwee
título: тест
Descrição: Описание

ID-ATUALIZACAO: 0000000002
COD-RASTREIO: qweqweqweqweqwee
título: test2
Descrição: description2

+0

Какая у вас проблема? –

+0

Первая часть должна была прочитать все записи из файла, но она застряла в цикле в этой части 'PERFORM UNTIL ARE-THERE-MORE-RECORDS = 'NO' READ ARQ-ATUALIZACAO' это не goinig внутри' AT END 'и' NOT AT END' –

+0

@JohnAnthonyRinehart No. Если это не 'AT END', то это' NOT AT END'. Нет среднего пути. Они являются взаимоисключающими, без альтернативного маршрута в рамках ПРОЧИТАНИЯ. –

ответ

2

Потому что у вас есть ACCESS RANDOM в вашем SELECT, действие по умолчанию для READ file-name (с no NEXT или KEY) - это считывание с клавиатуры.

Изменить что ACCESS SEQUENTIAL

Изменение, что в любом случае READ file-name NEXT, который явно последовательного чтения.

Я всегда использую явный NEXT или KEY на READ, чтобы не полагаться на поведение по умолчанию, которое зависит от типа файла (и типа OPEN).

Время, когда я забываю быть явным, когда я копирую чужой пример, не будучи достаточно осторожным, извините, я пропустил, что у вас не было СЛЕДУЮЩЕГО.

Потому что вы не используете OPEN I-O (вы не делаете никаких нажатий клавиш или START, поэтому вам не нужен RANDOM или DYNAMIC для доступа) просто используйте OPEN ... INPUT.

Вы не упомянули, что требует требование для ввода пользователем. Возможно, что, вероятно, нет необходимости вводить пользовательский ввод в цикл.

Вы не проверяете поле статуса файла после своего ОТКРЫТО. Вы обнаружите, что у вас есть проблема. Это плохая практика, чтобы открыть тот же файл несколько раз в одной и той же программы, даже при закрытии файла несколько раз (что вы не делаете, так что не будет проблемой там потенциально.


ОК, первый READ. OK, откройте сначала состояние FILE STATUS на SELECT.

Использование файла FILE STATUS в файле дает вам двухбайтовое поле, которое сообщает вам, что произошло с последней операцией ввода-вывода. Если это поле содержит ноль, все было в порядке.

Я бы рекомендовал использовать FILE STATUS для всех файлов, которые вы можете использовать, и проверить поле статуса файла (сохранить их уникальным для каждого файла) после каждого ввода-вывода в файле.

Использование файла FILE STATUS для файла сообщает COBOL время выполнения «Я собираюсь решить любые возникающие проблемы, вы скажете мне, когда возникла проблема, поместив код в это поле».

Если вы используете FILE STATUS и не проверьте поле статуса файла, ошибки ввода-вывода исчезнут.

Теперь вернемся к ЧИТАЮ.

Это читает следующую доступную запись.

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 
    UNTIL end-of-input-file 
    READ input-file 
    IF NOT end-of-input-file 
     PERFORM process-input 
    END-IF 
END-PERFORM 

Сравните этот то же самое с «грунтовочным чтением», который означает, что вы читали первую запись (если таковой имеется) перед началом цикла:

READ input-file 
PERFORM 
    UNTIL end-of-input-file 
    PERFORM process-input 
    READ input-file 
END-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   

Я сказал тест поле файла состояния после каждого ввода-вывода. Это заставило бы все выглядеть беспорядочно, так как этого избежать? ВЫПОЛНЕНИЕ:

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

Затем ЧТЕНИЯ вход-файл может проверять поле файла состояния (с 88 уровня) без кода хаотичным.

Дальнейшее совершенствование. У вас есть два ВЫПОЛНЯЕТ из «читать», но они не являются такими же, так называют их по-разному:

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 STATUS используется на SELECT, но не проверочные поля файла состояния (ST-ATUALIZACAO).

Второй ОТКРЫТО файл, который потерпит неудачу (файл уже открыт) в 300-STORE-NAME.

ЗАКРЫТЬ файла в 300-STORE-NAME. Что будет работать. Но теперь, когда вы делаете следующий READ, ваш файл закрыт. Поэтому READ не будет работать. Как он не будет работать (как в точности, что он будет делать)? Ну, Я думаю,, потому что Я не знаю, потому что Я не кодирую таким образом, что READ в закрытом файле с указанным FILE STATUS и AT END приведет к обработке AT END , Определенно, содержание уровня 01 под FD будет неопределенным.

Вы пытаетесь ПОИСК вашей таблицы каждый раз, когда вы добавляете запись в таблицу. Если вы делаете , необходимо, чтобы хранить все ваши записи в таблице, только ПОИСК, как только вы дошли до конца файла, и все в таблице.

После того, как у вас есть рабочая программа, есть еще один сайт StackExchange, называемый Code Review, где вы можете спросить, как лучше сделать рабочий код.

Сделать очень простую программу, которая считывает входной файл в цикле до конца файла.

В начале этой программы получить пользовательский ввод. Если имеется более одной части пользовательского ввода, сохраните его в таблице с помощью OCCURS.

Для каждой записи, которая считывается, проверяйте данные пользователя (одно поле или таблицу) и выдавайте результат, если вы получаете совпадение.

Посмотрите здесь ответы, Cobol Read statement format. Can it be redone a different way? и перейдите по ссылке. Обратите внимание на то, как использовать чтение прайминга и как использовать поле статуса файла, чтобы фактически проверять наличие ошибок и идентифицировать конец файла, пока он читается последовательно.

+0

Я использовал решение в той ссылке, которую вы дали, но я отлаживаю часть 'MOVE REG-ATUALIZACAO для ЗАПИСИ WS-RECORD (NAME-COUNT).' И я думаю, что она не может перемещать записи. Это приводит к незаконным данным о числовом поле в массиве. –

+0

@JohnAnthonyRinehart Существуют различные проблемы с вашей оригинальной программой. Я попытаюсь найти время, чтобы объяснить позже (если меня никто не бьет). Вы можете отредактировать свой вопрос (ссылку под вопрос), чтобы включить образец ваших входных данных. В то же время измените свои 9 (10) с на X (10) с. Нет необходимости иметь поле как числовое. –

+0

Спасибо за помощь, я попробовал взять строку 'NOT AT END' и просто иметь код внутри PERFORM (как вы писали выше), но это не сработало. Я попытаюсь изменить поля в алфавитном порядке позже. Я фактически меняю много оригинального кода, который я опубликовал с другими примерами из Интернета, но безрезультатно. –