适宜读者:(一年及以上主机经验)
背景知识:(PDS dataset基础知识,zOS基本知识,Java编程知识)
一、 JZOS基本功能介绍
JZOS工具集是一个Java本地接口库(JNI), 是由JAR文件和本地动态库构成。 此工具集提供的功能有:
-
以记录方式(record mode)高效地读写顺序数据集
-
实现了针对z/OS C程序库I/O函数的底层包装器
-
分配、删除、重命名MVS datasets的方法
-
执行单行、多行WTOs的方法
-
处理MVS Start, Modify, Stop命令的回调接口
-
调用z/OS Catalog Search (IGGCSI00)的方法
-
类com.ibm.jzos.ZUtil提供了如下z/OS 功能APIs
-
-
获取job/step/user names, process ids等
-
Write SMF records
-
Read environment variables
-
Read OS Memory
-
-
类com.ibm.jzos.PdsDirectory用来读取PDS directories
-
类com.ibm.jzos.ZLogstream用来读写、删除z/OS log streams
-
包com.ibm.jzos.wlm中的类用来访问z/OS Workload Manager (WLM)中的services
-
类com.ibm.jzos.MvsJobSubmitter用来从Java程序提交z/OS batch jobs
-
包com.ibm.jzos.fields中的类实现了从Cobol和Assembler数据类型转换到Java对象的功能
-
类com.ibm.jzos.DfSort提供了从Java调用DFSORT的接口
-
类com.ibm.jzos.AccessMethodServices提供了从Java调用IDCAMS的接口
-
类com.ibm.jzos.Enqueue通过ISGENQ service实现了对z/OS资源的序列化访问
二、 JZOS 对MVS Data Set I/O的支持
虽然JZOS提供了很多Java与z/OS交互的功能,但是本文主要关注的是Java读写z/OS Data Set的功能。由于JZOS是通过JNI调用z/OS C/C++库的I/O函数来操作z/OS PDS datasets的, 所以JZOS能够访问被z/OS C/C++库支持的任何MVS data sets. 包括:
-
Partitioned Data Set (PDS)
-
Partitioned Data Set Extended (PDSE)
-
Sequential Files
-
Virtual Sequential Access File (VSAM) of the type KSDS, RRDS, or ESDS
JZOS支持以下几种模式的I/O:
-
记录模式(Record Mode): 每次只读、写数据集中的一条记录(Record)
-
流模式(Stream Mode): 整个数据集是以字节流来表示的。 每次读、写只操作字节流中的一部分,不考虑记录边界的影响。
流模式又可以细分为两种类型:
- 文本流模式(Text stream mode): 在数据集记录转换成字节流的时候,删除每条记
录尾部的空格之后,在相邻记录间添加一个”new line”记录作为分隔符。
- 二进制流模式(Binary stream mode): 数据集记录直接转换成字节流,未添加任何
记录分隔符。
对MVS data sets的读写通常有3组可用APIs:
1. ZFile : 能够满足一般性的MVS data sets读写访问需求
ZFile既支持记录模式的文件读写,也支持流模式的文件读写。但ZFile不能用来打开POSIX(HFS/zFS)文件,只能打开被datasets name或是ddnames指向的MVS datasets.
下面是几个使用ZFile打开MVS datasets的例子:
ZFile dd = new ZFile("//DD:MYDD", "r");
//Opens the DD namee MYDD for reading
ZFile dsn = new ZFile("//'SYS1.HELP(ACCOUNT)'", "rt");
//Opens the member ACCOUNT from the PDS SYS1.HELP for reading text records
ZFile dsn = new ZFile("//SEQ", "wb,type=record,recfm=fb,lrecl=80,noseek");
//Opens the data set {MVS_USER}.SEQ for sequential binary writing.
2. FileFactory: 实现可移植(平台独立)的Text文件I/O
使用此类的最大好处是可以处理平台独立的Text文件I/O. FileFactory会根据打开文件的文件名判断底层的文件系统类型,如果文件名是以”//”开头,则使用ZFile获取文件的I/O流,否则使用java.io获取文件流。
使用BufferedReader以text stream模式读取MVS datasets的例子:
BufferedReader rdr = FileFactory.newBufferedReader("//DD:INPUT");
try {
String line;
while ((line = rdr.readLine()) != null) {
System.out.println(line);
}
} finally {
rdr.close();
}
3. RecordReader/RecordWriter: 实现高速的Data set记录式I/O访问
如果只想以记录的模式来读写顺序数据集,可以通过com.ibm.jzos.RecordReader和com.ibm.jzos.RecordWriter来完成。RecordReader和RecordWriter通过JNI调用z/OS Basic Sequential Access Method (BSAM)来访问z/OS数据集。这被认为是最高效地记录式文件读写。通常CPU的使用率会降低60-70%.
例子如下:
RecordReader reader = null;
try {
reader = RecordReader.newReader("//my.dataset", ZFileConstants.FLAG_DISP_SHR);
byte[] recordBuf = new byte[reader.getLrecl()];
while ((bytesRead = reader.read(recordBuf)) >= 0) {
...
}
} finally {
if (reader != null) {
reader.close();
}
}
三、 使用JZOS遍历读取MVS data set members的实例
完整的例子如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.ibm.jzos.FileFactory;
import com.ibm.jzos.PdsDirectory;
import com.ibm.jzos.ZFile;
public class PdsTraverser
{
public static List<String> readLines(final String filename) throws IOException
{
final List<String> lines = new ArrayList<String>();
InputStream inputStream = null;
BufferedReader br = null;
String line = null;
try
{
inputStream = FileFactory.newInputStream(ZFile.getSlashSlashQuotedDSN(
filename, true));
br = new BufferedReader(new InputStreamReader(inputStream));
while ((line = br.readLine()) != null)
{
lines.add(line);
}
return lines;
}
finally
{
br.close();
}
}
public static void main(final String[] args) throws IOException
{
if (args.length != 1)
{
System.err.println("Usage: please specify an PDS dataset to traverse, eg: 'HLQ.MYDATA' ");
return;
}
final String fileName = args[0].trim();
System.out.println("The PDS dataset you specify: " + fileName);
final String ddname = "TESTDD";
String cmd = "alloc fi(" + ddname + ") da(" + fileName + ") vol(ZDSYS1) shr";
Zfile.bpxwdyn(cmd);
final PdsDirectory pdsDir = new PdsDirectory("//DD:TESTDD");
final Iterator it = pdsDir.iterator();
StringBuffer memName;
while (it.hasNext())
{
final PdsDirectory.MemberInfo mem = (PdsDirectory.MemberInfo) it.next();
final PdsDirectory.MemberInfo.Statistics stat = mem.getStatistics();
System.out.println("Member Name: " + mem.getName());
System.out.println("create: " + stat.creationDate);
System.out.println("userid: " + stat.userid);
memName = new StringBuffer();
memName.append(fileName.substring(0, fileName.length() - 1));
memName.append("(" + mem.getName() + ")");
System.out.println("========Text in " + mem.getName() + "========");
final List<String> lines = readLines(memName.toString());
final Iterator<String> linesIt = lines.iterator();
while (linesIt.hasNext())
{
System.out.println(linesIt.next());
}
}
cmd = "free fi(TESTDD)";
ZFile.bpxwdyn(cmd);
}
}
以下内容是对上面例子的分析:
1. 使用BPXWDYN动态分配一个DDName指向要访问的data set
对于一个uncatlog的dataset, 必须先根据dataset name和所处的volume分配DDName,然后通过DDName打开文件,否则会提示找不指定文件(因为zFile构造方法没有volume参数)。
//code segment for DDName allocation
String ddname = “TESTDD”;
String cmd = "alloc fi("+ddname+") da(HLQ.MYDATA) vol(MYVOLUMN) shr";
Zfile.bpxwdyn(cmd);
2. 遍历PDS dataset directory,逐个获取PDS data set member信息
//code segment for traversing PDS dataset directory
PdsDirectory pdsDir = new PdsDirectory("//DD:TEMPDD");
@SuppressWarnings("unchecked")
final Iterator<PdsDirectory.MemberInfo> it = pdsDir.iterator();
while (it.hasNext())
{
final PdsDirectory.MemberInfo member = it.next();
...
}
3. 读取PDS dataset member的信息
//以记录的方式读取dataset member中的信息
// memberName需满足格式: “//HLQ.MYDATASET(MEMBER)”
BufferedReader rdr = FileFactory.newBufferedReader(memberName.toString());
String line;
while ((line = rdr.readLine()) != null)
{
//处理member内容的逻辑
...
}
4. 使用BPXWDYN释放掉分配的DDName
由于DDName也是系统的一种资源,如果及时不释放,会导致资源不足的问题。
// code segment to free DDName
String cmd = “free fi(TEMPDD)”;
Zfile.bpxwdyn(cmd);
JZOS提供很多方便易用的APIs使Java程序与z/OS系统间的交互变得更加便利。本文只是简单介绍了JZOS在处理MVS dataset I/O方面的接口,后续还会介绍JZOS如何使得Java程序能够提交batch作业,以及解析return code, 与system console交互相关的接口和用法。
更多更详细的资料可以参考:
JZOS Batch Launcher and Toolkit Installation and User's Guide SA38-0696-03
jzos_javadoc: http://www.ibm.com/developerworks/java/zos/javadoc/jzos/SDK7/index.html
作者:周运杰
邮箱:yunjiezATcn.ibm.com(替换AT为@)
内容声明:本文仅代表作者的个人观点,与IBM立场、策略和观点无关。文中专业名词因翻译原因,表述中难免存在差异。如有疑惑,请以英文为准。同时数据来源于实验室环境,仅供参考。如果您对我们的话题感兴趣,请通过电子邮箱联系我们。