0

我正在提交一个 JCL 作业以在 Mainframe 中分配一个 VB 数据集。提交作业后,数据集创建成功。

然后我在大型机的 omvs 区域运行一个 java 程序,打开文件并将一些内容写入其中。当我尝试将数据写入文件时,出现以下错误。

//DD:SYS00011 : fwrite() 失败。EDC5024I 尝试关闭已由另一个线程打开的文件。errno=24 errno2=0xc0640021 last_op=0 错误代码=0x0。

JCL提交分配数据集:

//USERNAME JOB ABC,,NOTIFY=&SYSUID,CLASS=F,MSGLEVEL=(1,1),MSGCLASS=X 
//STEP1 EXEC PGM=IEFBR14 
//STEP DD DSN=ASD00T.SM.ULRL, 
// DISP=(NEW,CATLG,DELETE), 
// UNIT=SYSDA,SPACE=(1,(10,60),RLSE),AVGREC=M, 
// DCB=(RECFM=VB), 
// DSORG=PS

编写文件的代码:

zFileIn = new ZFile("//'ASD00T.INPUT.ULRL'", "rb,type=record,noseek");
if (zFileIn.getDsorg() != ZFile.DSORG_PS) {
throw new IllegalStateException("Input dataset must be DSORG=PS");
 }
zFileOut = new ZFile("//'ASD00T.SM.ULRL'", "wb,type=record,noseek, recfm="+ zFileIn.getRecfm()+ ", lrecl="+ zFileIn.getLrecl());
long count = 0;
byte[] recBuf = new byte[zFileIn.getLrecl()];
int nRead;
while((nRead = zFileIn.read(recBuf)) >= 0) {
zFileOut.write(recBuf, 0, nRead);
count++;
}
4

1 回答 1

1

您的问题的核心是您需要在完成编写后调用 ZFile.close() 方法。这样做可以保证打开、写入和关闭都发生在同一个线程下,你应该没问题。这是使用传统数据集而不是 USS 文件的副作用。

其原因很复杂,但这与在 z/OS 中“常规”QSAM/BSAM/VSAM 数据集的行为与 UNIX 文件系统文件略有不同的事实有关。

如果您正在写入 UNIX 文件(HFS、ZFS、NFS 等)而不是传统数据集,那么您正在做的事情会非常好......这是因为 USS 以不同的方式对待资源所有权 - 文件句柄拥有进程级别,而不是线程。当您打开一个 USS 文件时,该文件句柄可以被进程中的任何线程使用或关闭……这是各种 UNIX 标准规定的,因此 z/OS 只能以这种方式工作。

传统的数据集有点不同。当您打开常规数据集时,定义打开文件的操作系统结构存储在内存中,该内存锚定到打开文件的线程。文件句柄中有足够的信息,您可以从其他线程执行 I/O,但关闭文件需要从打开文件的线程进行。

现在,由于您的代码中似乎没有 close() ,因此该文件将保持打开状态,直到您的 Java 线程结束。当您的 Java 线程结束时,系统运行时将获得控制权,以清理您可能已分配的任何资源。它看到挥之不去的打开文件并尝试关闭它,但现在它没有在打开文件的线程下运行,所以你得到你所看到的失败。

通常,UNIX 文件和 z/OS 数据集的工作方式几乎完全相同,但这个问题是细微差别之一。IBM 从标准合规性的角度来看没有这样做,因为 z/OS 数据集不是任何标准的一部分,而且通常它们可以互换使用的方式是一个很棒的特性。

顺便说一句,所有这些都在 LE(语言环境)和 C 运行时参考的细则中详细说明。

于 2017-04-07T14:45:14.340 回答