- 论坛徽章:
- 0
|
JAVA 读取AS400上的文件是,通过SQL语句方式无法直接读取成员,需要通过AS400程序的OVRDBF操作进行访问路径更改,此方法需要在AS400上建立程序,通过存储过程返回游标实现。
其实IBM的JTOpen提供的IFS文件访问方式完全可以实现AS400上RPG程序所能提供的文件的操作,比如SetLL,SetGt,Read,ReadE,ReadP,Chain等。下面发一个简单例子,例子内容为通过IFS方式读取指定源码(即某个PF下的指定Mbr)
以下操作均需要引用jt400.jar包,该jar包可在IBM官网下载到,不过需要注意AS400系统版本与jar包版本的关系,相关文档官网都有介绍。
1) 首先创建一个AS400系统连接对象。
//创建AS400对象,参数为主机IP,用户名,用户密码
AS400 system = new AS400(host, userName, password);
//以下内容为非必须设置
system.setShowCheckboxes(false); //设置登录异常不弹出登录框
system.setCcsid(138 ; //设置连接的ccsid值,详细CCSID值列表官网有结束,论坛也有。
//设置连接侦听器
system.addConnectionListener(new ConnectionListener(){
//设置连接成功处理
public void connected(ConnectionEvent arg0) {
// TODO Auto-generated method stub
Job myjob = new Job(system) ; //获取连接的JOB
//输出当前JOB信息
Logger.getLogger(ManageConnectAs400.class).info("AS400系统已连接。" ;
Logger.getLogger(ManageConnectAs400.class).info("AS400系统名:"+system.getSystemName());
Logger.getLogger(ManageConnectAs400.class).info("AS400登录用户名:"+system.getUserId());
}
//设置断开连接处理
public void disconnected(ConnectionEvent arg0) {
// TODO Auto-generated method stub
Logger.getLogger(ManageConnectAs400.class).info("AS400系统连接已断开。" ;
}
});
2) 创建转换参数为IFS文件访问路径的方法
/**
* 转换指定参数为文件路径
* @param lib 库名
* @param obj 对象名
* @param objType 对象类型
* @param mbr 成员名
* @return 库名不能为null和空,否则返回null,成员名如为空则取对象的默认成员,如只输入库名,则自动转换为QSYS.LIB/LIB.LIB。
*/
public static String getObjPath(String lib,String obj,String objType,String mbr ){
if(lib!=null && obj!=null && objType!=null
&& !lib.trim().equals(""
&& !obj.trim().equals(""
&& !objType.trim().equals("" ){
if(mbr!=null && !mbr.trim().equals("" ){
return new QSYSObjectPathName(lib,obj,mbr,objType).getPath();
}else{
return new QSYSObjectPathName(lib,obj,objType).getPath();
}
}else{
if(lib!=null && !lib.trim().equals(""
&& (obj==null || obj.trim().equals("" )
&& (objType==null || objType.trim().equals("" ) ){ //只输入库名
return new QSYSObjectPathName("QSYS",lib,"LIB" .getPath();
}
return null ;
}
}
3) 创建获取指定文件记录格式的的方法
/**
* 获取指定文件的记录格式 SQL方式
* @param filePath 文件访问路径
* @return 获取到的文件记录格式对象,如文件不存在,则返回null
* @throws IOException
* @throws AS400SecurityException
* @throws ErrorCompletingRequestException
* @throws InterruptedException
* @throws ObjectDoesNotExistException
* @throws SQLException
*/
public static RecordFormat getRecordFormatOfSql(String filePath) throws IOException, AS400SecurityException, ErrorCompletingRequestException, InterruptedException, ObjectDoesNotExistException, SQLException{
if(isFileExist(filePath)){ //检查文件是否存在
QSYSObjectPathName qpath = new QSYSObjectPathName(filePath);
//创建文件记录格式,官网有介绍使用AS400FileRecordDescription对象的retrieveRecordFormat方法,但此方法有局限性,对非系统表支持不完备。
return createRecordFormat.getRecordFormat(qpath.getLibraryName(), qpath.getObjectName());
}else{
return null ;
}
}
/**
* 获取指定文件的记录格式。
* @param lib 库名
* @param file 文件名
* @return
* @throws SQLException
*/
public static RecordFormat getRecordFormat(String lib,String file) throws SQLException{
//获取字段列表
Vector<Object> flds =getFields(lib,file);;
//获取文件键字字段列表
Vector<Object> keyflds =getKeyFields(lib,file);
List<FieldDescription> fieldList = new ArrayList<FieldDescription>();
List<String> KeyFieldList = new ArrayList<String>();
//取到字段列表
if(flds!=null && flds.size() > 2){
int size = flds.size();
//String[] fldNames = (String[])flds.get(0);
String[] values = null ;
String fldName = "";
String formatName = "";
String fldType = "";
int charLen =0 ;
int ccsid = 0 ;
int fldLen = 0;
int fldScale = 0;
for(int i=2 ;i<size;i++){
values = (String[])flds.get(i);
fldName = StringUtil.rightTrim(values[3]).toUpperCase();
formatName = StringUtil.rightTrim(values[2]);
fldType = values[6];
fldLen = Integer.parseInt(values[5]);
//S型 对应的 JAVA类型为 ZonedDecimalFieldDescription
if(fldType.trim().toUpperCase().equals("S")){
fldLen = Integer.parseInt(values[8]);
fldScale = Integer.parseInt(values[9]);
fieldList.add(new ZonedDecimalFieldDescription(
new AS400ZonedDecimal(fldLen,fldScale),
fldName));
}else if(fldType.trim().toUpperCase().equals(" ")){
//P型 对应的 JAVA类型为 PackedDecimalFieldDescription
fldLen = Integer.parseInt(values[8]);
fldScale = Integer.parseInt(values[9]);
fieldList.add(new PackedDecimalFieldDescription(
new AS400PackedDecimal(fldLen,fldScale),
fldName));
}else if(fldType.trim().toUpperCase().equals("A") ){
//A型对应的JAVA类型为CharacterFieldDescription
charLen = Integer.parseInt(values[10]);
ccsid = Integer.parseInt(values[11]);
fieldList.add(new CharacterFieldDescription(
new AS400Text(charLen,ccsid),
fldName));
}else if(fldType.trim().toUpperCase().equals("O")){
//O型 对应的JAVA类型为DBCSOpenFieldDescription
charLen = Integer.parseInt(values[10]);
ccsid = Integer.parseInt(values[11]);
fieldList.add(new DBCSOpenFieldDescription(
new AS400Text(charLen,ccsid),
fldName));
}else if(fldType.trim().toUpperCase().equals("B")){
//B型 对应的JAVA类型为BinaryFieldDescription
if(fldLen==2){
fldLen = Integer.parseInt(values[8]);
fieldList.add(
new BinaryFieldDescription(
new AS400Bin2(),
fldName,
fldName,
fldLen)
);
}else if(fldLen==4){
fldLen = Integer.parseInt(values[8]);
fieldList.add(
new BinaryFieldDescription(
new AS400Bin4(),
fldName,
fldName,
fldLen)
);
}else if(fldLen== {
fldLen = Integer.parseInt(values[8]);
fieldList.add(
new BinaryFieldDescription(
new AS400Bin8(),
fldName,
fldName,
fldLen)
);
}else{
//不支持的类型
System.out.println(fldLen);
}
}else{
//其他类型暂不处理
System.out.println(fldType.trim().toUpperCase());
}
}
//判断键字是否为空
if(keyflds!=null){
//设置键字
size = keyflds.size();
for(int i=2 ;i<size;i++){
values = (String[])keyflds.get(i);
fldName = values[3];
KeyFieldList.add(fldName);
}
}
//创建记录格式对象,格式名为取到的记录格式名
RecordFormat format = new RecordFormat(formatName);
//设置记录格式字段列表
for (int i = 0; i < fieldList.size(); i++) {
format.addFieldDescription(fieldList.get(i));
}
//设置记录格式键字字段列表
for (int i = 0; i < KeyFieldList.size(); i++) {
format.addKeyFieldDescription(KeyFieldList.get(i));
}
return format;
}else{
return null ;
}
}
/**
* 获取字段列表
* @param lib
* @param file
* @return
* @throws SQLException
*/
private static Vector<Object> getFields(String lib,String file) throws SQLException{
//此处为执行SQL查询返回查询结果的方法,具体实现就不发了,大家应该能自己解决
return UtilJdbcAs400.executeSelectSql(
"SELECT DBILIB, DBIFIL, DBIFMT, DBIFLD, DBIATR,DBIILN,DBIITP,DBITYP,DBINLN,DBINSC,DBICLN,DBICCC FROM QSYS/qadbifld where DBILIB ='" +
lib.trim().toUpperCase()+"' and DBIFIL ='"+ file.trim().toUpperCase()+"'");
}
/**
* 获取键字字段列表
* @param lib
* @param file
* @return
* @throws SQLException
*/
private static Vector<Object> getKeyFields(String lib,String file) throws SQLException{
//此处为执行SQL查询返回查询结果的方法,具体实现就不发了,大家应该能自己解决
return UtilJdbcAs400.executeSelectSql(
"SELECT DBKLIB, DBKFIL, DBKFMT, DBKFLD, DBKPOS FROM QSYS/QADBKFLD where DBKLIB ='" +
lib.trim().toUpperCase()+"' and DBKFIL ='"+ file.trim().toUpperCase()+"' ORDER BY DBKPOS");
}
4) 创建读取文件的方法
/**
* 读取文件所有记录,返回结果集
* @param filePath 文件访问路径
* @param format 记录格式对象
* @return
*/
public static Vector<Object[]> readFileAll(String filePath,RecordFormat format) {
AS400 system;
try {
//判断文件是否存在
if(isFileExist(filePath)){
system = ManageConnectAs400.getSystem();
Vector<Object[]> vc = new Vector<Object[]>(800000);
//创建文件键字读取对象
SequentialFile file = new SequentialFile(system,filePath);
//设置文件记录格式
file.setRecordFormat(format);
//以只读方式切不进行任何锁操作打开文件
file.open(AS400File.READ_ONLY, 1,
AS400File.COMMIT_LOCK_LEVEL_NONE );
//读文件
Record record = file.readFirst();
int len = 0 ;
if(record!=null){
vc.add(format.getFieldNames()); //字段信息
while(record!=null ){
//while(true){
vc.add(record.getFields());
len ++ ;
while(true){ //此处存在一定缺陷,正在查找原因,在读取系统表的中文字段时会报错。
try {
record = file.readNext();
break ;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("readNextErrorNum:"+record.getRecordNumber());
}
}
}
file.close();
return vc ;
}else{
file.close();
return null ;
}
}else{
return null ;
}
} catch (AS400SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ErrorCompletingRequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ObjectDoesNotExistException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null ;
}
5) 最后就是对返回值的处理的。返回结果格式与通过SQL查询文件获取到格式一致。
总结:
IFS方式读取文件首先需要获取文件访问路径,一般为/QSYS.LIB/LIB.LIB/FILE.FILE/MBR.MBR(详细信息可以查看JT400API文档中的QSYSObjectPathName对象说明)。而后需要获取文件的记录格式对象RecordFormat(即内容转码对象),此时有多种处理方法,一是对RecordFormat对象进行继承或创建,二是使用AS400FileRecordDescription对象进行获取,但AS400FileRecordDescription方法有使用局限,个人建议使用第一种方法,对某些特殊表,比如中文字段ccsid定位为937(繁体中文)而实际存储内容为935(简体中文)的表,可在创建记录格式是设置指定字段的ccsid,这样获取到的数据就会是935(简体中文)而不是937(繁体中文)的乱码。SQL方式查询表有这种乱码问题如无法修改表的的情况下,可通过反射机制修改指定字段的ccsid值来实现。
最后通过文件访问路径和文件记录格式创建文件对象,此时有两种选择SequentialFile(序列文件对象)和KeyedFile(键字文件对象),SequentialFile支持相对记录号读取,KeyedFile支持按指定键字读取。
|
|