Как использовать DISP = SHR на fopen - PullRequest
2 голосов
/ 29 мая 2020

С кодом, например:

fopen("DD:LOGLIBY(L1234567)", "w");

и JCL, например:

//LOGTEST  EXEC PGM=LOGTEST
//LOGLIBY  DD   DSN=MYUSER.LOG.LIBY,DISP=SHR

Я могу создавать элементы PDS (E), одновременно просматривая PDS (E), чтобы посмотреть у существующих участников, как и ожидалось, с DISP=SHR.

Если вместо этого я кодирую:

fopen("//'MYUSER.LOG.LIBY(L1234567)'", "w");

fopen не работает, если я просматриваю PDS (E) в то время, или просматриваю PDS (E) не работает, пока у меня открыт файл. Другими словами, DISP=SHR нет. Согласно документации fopen(), DISP=SHR является значением по умолчанию при использовании файловых режимов «r» и c, но не «w».

Как я могу указать DISP=SHR во втором примере ?

1 Ответ

3 голосов
/ 05 июня 2020

Есть две возможности ...

Для тех, кто не знаком с внутренней структурой секционированных наборов данных (то есть PDS или PDS / E), эти наборы данных логически разделены на две части: «каталог» "имея указатели на все отдельные элементы, и область" данных ", содержащую фактические записи для отдельных элементов:

PDS: <DIRECTORY BLOCKS>
        <MEMBER1>: ADDRESS OF DATA FOR MEMBER1 (xxx)
        <MEMBER2>: ADDRESS OF DATA FOR MEMBER2 (yyy)
         ...
        <DIRECTORY FREESPACE)
         ... 
     <EOF - END OF THE PDS DIRECTORY>

     <DATA PORTION>
     +xxx = DATA FOR MEMBER1
            ...
            <EOF - END OF MEMBER1>
     +yyy = DATA FOR MEMBER2
            ...
            <EOF - END OF MEMBER2>
     ...
     FREE SPACE (ALLOCATED, BUT UNUSED)
     ...
     END OF PDS 

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

Во-первых, если у вас действительно есть оператор DD, закодированный так, как вы показываете в вопросе, тогда вам может просто потребоваться изменить ваше открытие с fopen(dsn,...) на fopen(dd:ddname,...). Если вы работаете в оболочке UNIX или делаете что-то, что приводит к тому, что ваш процесс работает в другом адресном пространстве (например, fork ()), то это может не сработать, но, возможно, стоит попробовать. Если вы сделаете это с помощью JCL, который вы показываете, проблема будет в управлении каталогом PDS / E - вам нужно будет создать свой собственный "STOW" при создании / обновлении нового члена, поскольку JCL выделяет весь набор данных, а не только одинокий член. Последовательность будет следующей:

  1. Откройте DD для вывода.
  2. Запишите свои данные.
  3. Обновите каталог PDS или PDS / E информацией о новом члене (это здесь появляется функция STOW - она ​​обновляет каталог PDS / PDSE, чтобы отразить член, который вы создали или обновили).
  4. Закройте файл

Если вам также нужно read members, вам нужно будет выполнить FIND (или BLDL / POINT - который может быть fseek () в C), чтобы указать на правильный член, а затем прочитать член. Я уверен, что это звучит сложно, но преимущество этого подхода в том, что вы можете выделить / открыть файл один раз и обработать столько отдельных членов, сколько захотите.

Второй обходной путь может заключаться в том, чтобы динамически выделить файл самостоятельно, а затем открыть его, используя синтаксис DD:ddname ... если вы нечасто обращаетесь к файлу, это, вероятно, проще закодировать. Кровавые детали распределения динамических c полностью описаны здесь: https://www.ibm.com/support/knowledgecenter/SSLTBW_2.4.0/com.ibm.zos.v2r4.ieaa800/reqsvc.htm.

Есть несколько способов вызвать динамическое c распределение: вы можете написать небольшую программу на ассемблере, можно использовать вызываемую службу BPXWDYN z / OS UNIX Services или функции среды выполнения C "dynallo c ()" или "svc99 ()". Функция dynallo c () проста в использовании, но она раскрывает только часть того, что может сделать динамическое c распределение ... svc99 () более громоздко в использовании, но предоставляет больше функциональных возможностей.

Как бы вы это ни делали, динамическое c распределение требует «текстовых единиц», которые примерно соответствуют параметрам, которые вы найдете в операторах JCL DD. То, что вы описываете, звучит так, будто вам просто нужно передать текстовые блоки DSN и DISP и, возможно, DDNAME (вы можете либо передать свое собственное DDNAME, либо позволить системе сгенерировать его для вас).

Функции времени выполнения C упрощают все это, но имейте в виду, что есть несколько странностей, таких как необходимость дополнить параметры до максимальной длины. Например, DSN должен состоять из 44 символов и дополнен пробелами справа, а не строкой с завершающим нулем в стиле C.

Вот небольшой фрагмент кода в качестве примера:

#include <dynit.h> 
. . .

int allocate(ddn, dsn, mem)
{
__dyn_t   ip;                    // Parameters to dynalloc()
 . . . 

 // Prepare the parameters to dynalloc()

 dyninit(&ip);                   // Initialize the parameters
 ip.__ddname     = ddn;          //  8-char blank-padded
 ip.__dsname     = dsn;          // 44-char blank-padded
 ip.__status     = __DISP_SHR;   // DISP=(SHR)
 ip.__normdisp   = __DISP_KEEP;  // DISP=(...,KEEP)
 ip.__misc_flags = __CLOSE;      // FREE=CLOSE
 if (*mem)                       // Optional PDS, PDS/E member 
     ip.__member = mem;          //  8-char blank-padded

 // Now we can call dynalloc()...

 if (dynalloc(&ip))              // 0: Success, else error 
 {
     // On error,  the errcode/infocode explain why - values 
     // are detailed in z/OS Authorized Services Reference

     printf("SVC99: Can't allocate %s - RC 0x%x, Info 0x%x\n", 
            dsn, ip.__errcode, ip.__infocode);
     return FALSE;
 }

 // If dynalloc works, you can open the file with fopen("DD:ddname",...)

}

Не забывайте, что когда вы закончите работу с файлом, вам обычно нужно освободить его. В приведенном выше фрагменте кода используется «FREE = CLOSE» - это означает, что при закрытии файла z / OS автоматически освобождает выделение… если вы открываете и обрабатываете набор данных только один раз, это удобный подход. Если вам нужно неоднократно открывать и закрывать файл, вы не будете использовать FREE = CLOSE, а вместо этого вызовите динамическое c распределение во второй раз после того, как вы закончите свою обработку и захотите освободить файл.

Если вам нужен одновременный доступ к нескольким файлам, имейте в виду, что вам нужно будет сгенерировать несколько уникальных DDNAME. Вы можете сделать это в своем собственном коде или использовать форму динамического c выделения, которая автоматически создает и возвращает пригодное для использования DDNAME (в форме «SYSnnnnn»).

Также не забывайте, что обновление набора данных с помощью DISP = SHR может быть опасным в некоторых ситуациях, особенно если задействованный набор данных может быть как обычным PDS, так и PDS / E. Большая опасность заключается в том, что два приложения одновременно открывают набор данных для вывода ... оба будут записывать данные в одно и то же место, и результатом, скорее всего, будет поврежденный каталог PDS.

В среде UNIX Services есть и другие странности, особенно если вы используете fork () или exe c () и ожидаете, что дескрипторы файлов будут работать в подпроцессах, поскольку выделения обычно привязаны к конкретному z Адресное пространство / OS. Такие службы, как spawn (), могут позволить дочернему процессу работать в том же адресном пространстве, поэтому это одна из возможностей.

...