如何在Fopen上使用DISP = SHR

问题描述 投票:1回答:1

使用类似代码:

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");

如果我当时正在浏览PDS(E),则打开失败,或者当我打开文件时,PDS(E)的浏览失败。换句话说,没有DISP=SHR。根据fopen()文档,当使用“ r”等文件模式而不是“ w”文件模式时,DISP=SHR是默认设置。

如何在第二个示例中提供DISP=SHR

fopen mainframe zos
1个回答
2
投票

有两种可能...

对于不熟悉分区数据集(即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 Shell下运行,或者执行了某些操作导致进程在不同的地址空间中运行(例如fork()),则此操作可能无效,但值得尝试。如果使用显示的JCL执行此操作,那么挑战将是管理PDS / E目录-创建/更新新成员时,您将需要发出自己的“ STOW”,因为JCL会分配整个数据集,而不仅仅是一个成员。顺序为:

  1. 打开DD进行输出。
  2. 写您的数据。
  3. 用新的成员信息更新PDS或PDS / E目录(这是STOW功能所在的位置-它更新PDS / PDSE的目录以反映您创建或更新的成员)。
  4. 关闭文件

如果还需要读取成员,则需要发出FIND(或BLDL / POINT-在C语言中可以为fseek())以指向正确的成员,然后读取该成员。我敢肯定这听起来很麻烦,但是这种方法的优点是您可以分配/打开文件一次,并根据需要处理任意数量的单个成员。

第二种解决方法可能是自己动态分配文件,然后使用DD:ddname语法打开它...如果仅不经常访问该文件,则可能更易于编码。动态分配的详细内容在此处有完整描述:https://www.ibm.com/support/knowledgecenter/SSLTBW_2.4.0/com.ibm.zos.v2r4.ieaa800/reqsvc.htm

有几种方法可以调用动态分配:您可以编写一个小的汇编程序,可以使用z / OS UNIX服务BPXWDYN可调用服务,也可以使用C运行时“ dynalloc()”或“ svc99()”功能。 dynalloc()函数易于使用,但是它仅公开了动态分配可以执行的操作的子集... svc99()使用起来比较麻烦,但是却提供了更多功能。

但是,动态分配采用的“文本单元”大致与您在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,而是在处理完毕并想释放文件后再次调用动态分配。

[如果需要同时访问多个文件,请注意,您需要生成多个唯一的DDNAME。您可以在自己的代码中执行此操作,也可以使用动态分配的形式自动生成并返回可用的DDNAME(形式为“ SYSnnnnn”)。

此外,请不要忘记在某些情况下,在DISP = SHR下更新数据集可能很危险,特别是如果所涉及的数据集既可以是常规PDS也可以是PDS / E。最大的危险是两个应用程序同时打开数据集以进行输出...两者都会将数据写入同一位置,结果可能是损坏的PDS目录。

在UNIX Services环境中,还有其他一些奇怪之处,特别是如果您使用fork()或exec()并希望文件句柄在子进程中工作,因为分配通常与特定的z / OS地址空间相关。诸如spawn()之类的服务可以使子进程在相同的地址空间中运行,因此这是一种可能性。

© www.soinside.com 2019 - 2024. All rights reserved.