java odbc dbf_通过java动态创建ODBC数据源来访问DBF文件

想用java语言来处理。最终还是需要通过JNI来处理,不过用到了一个开元的操作注册表的registry-3.1.3,使用后,发现蛮简单的,网上已有很多资料介绍,就不多说了。

想了两种解决方法,第一种比较麻烦,但是看网上很多人问,就也总结了出来,其实就是通过java动态创建ODBC数据源来访问DBF文件,这个就需要用到registry,来修改注册表了。

其实,主要是动态创建ODBC数据源,开始很简单,可以手工设置一次数据源,当然也可以通过程序直接生成,问题都不大。下面只说怎样修改。

import com.ice.jni.registry.RegStringValue;

import com.ice.jni.registry.Registry;

import com.ice.jni.registry.RegistryKey;

public class TestC {

public static void main(String[] str) {

try {

RegistryKey child = Registry.HKEY_CURRENT_USER

.openSubKey("Software").openSubKey("ODBC").openSubKey

("ODBC.INI").openSubKey("data_0930",RegistryKey.ACCESS_ALL);//

操作权限是通过RegistryKey来获取的。

String de = "F:\\commony\\test\\data\\070901"; //

我的DBF数据的目录//其中,data_0930是我第一次设置的数据源的一个注册表的名称

System.out.println(child.getStringValue("SourceDB"));

child.setValue(new RegStringValue(child,"SourceDB",de));

System.out.println(child.getFullName());

} catch (Exception e) {

e.printStackTrace();

}

}

}

然后就是通过,sun.jdbc.odbc.JdbcOdbcDriver来获取数据,

import java.sql.DriverManager;

import java.sql.*;

public class TestOdbc {

public TestOdbc() {

}

public static void main(String[] args) {

java.sql.Connection conn = null;

java.sql.PreparedStatement pt = null;

java.sql.ResultSet rs = null;

try {

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

}

catch (ClassNotFoundException ex1) {

}

try {

conn = DriverManager.getConnection("jdbc:odbc:data_0930", "", "");

pt = conn.prepareStatement(" select * from test_table");

rs = pt.executeQuery();

while(rs.next()){

System.out.println("==="+rs.getString(1));

System.out.println("==="+rs.getString(2));

System.out.println("==="+rs.getString(3));

System.out.println("==="+rs.getString(4));

System.out.println("==="+rs.getString(5));

}

}

catch (SQLException ex) {

}

}

}

其实真的很简单。

其实,文件名,是可以动态获取的,一般可以通过java中的File类来获取:

import java.io.File;

public class TestD {

public static void main(String[] args){

File file = new File("F:\\commony\\test\\data");

File[] df = file.listFiles();

for(int k =0;k if(df[k].isDirectory()){ //

因为文件夹中包含DBF文件,所以判断是文件夹,而不是文件

System.out.println("===kkkk=="+k+"====="+df[k].getName());

}

}

}

}

第一种就是这样,需要注意的是registry的使用,其实很简单的,只要把DLL文件放到classpath下就可以了。

第二种其实更简单,就是通过另一个开元的类包jdbf.jar,使用方法也很简单,网上有很多资料,可以查询。也就不多说了。

完全free的JDBF: http://www.svcon.com/ 这个网站主要是做数据库连接中间介的,其中用到了一个他们自己开发的叫做JDBF的项目,该项目就是专门控制dbf文件的,整个包只有30K大小,你们随便用个工具反编译一下就可以看懂里面的代码,很简单,就是按照具体格式处理文件!(注意,不是使用JDBC连接的。)

JDBF不能读取中文问题的解决方法:JDBF对于数据的读取采用了UNICODE字符集,所以读取数据的时候不存在问题。关键在于对字段的读取不兼容中文。

打开JDBF的源码就知道,它是把.dbf作为文件流的形式读进来的,但是我不明白它为什么读取字段和读取数据要分两种方式。读取字段的时候它是这样的:从文件流中一个一个byte(字节)地读取信息,却画蛇添足地把每个字节强行转化为字符(char)型,然后再把这一传char拼接成一个String字段。

这样就有问题了,在JAVA中一个char的大小是一个byte的两倍,这样的话,就相当于每个char的高位填入了一个为0000的空byte,对于使用高位的中文字符集来说,它就相当于每次读取了半个中文字符,然后就把这半个字符用补零的方法转换成整个中文字符,这就是JDBF不能读取中文字段名的原因。(所幸的是它在读取数据的时候却没有采用逐个byte读取的方式,所以不会出现问题。)

还有一点幸运的是,它读进来的字段虽然是错的,但是字段里面所含的信息没有丢失,我们只要把它人为填加的0000空byte去掉就可以转回真正的中文。

知道了原因,就很好解决了,下面是别人写的一个转换函数,你在通过String columnName=DBFReader.getField(i).getName()得到每一个字段的时候使用这个函数转换,就可以转回正确的汉字。

//遍历字串的每一个char,转换成byte后组合成byte[],再转换成String返回

//****可以解决因逐个读入char(而不是byte)而组成的字串不能通过encoding还原成中文的问题****

public static String getStrByCharToByte(String str){

byte[] temp=new byte[str.length()];

for(int i=0;i temp[i]=(byte)(str.charAt(i));

return new String(temp);

}

部分CODE

public class DBFReader {

public DBFReader(String s) throws JDBFException {

stream = null;

fields = null;

nextRecord = null;

try {

init(new FileInputStream(s));

}

catch (FileNotFoundException filenotfoundexception) {

throw new JDBFException(filenotfoundexception);

}

}

public DBFReader(InputStream inputstream) throws JDBFException {

stream = null;

fields = null;

nextRecord = null;

init(inputstream);

}

private void init(InputStream inputstream) throws JDBFException {

try {

stream = new DataInputStream(inputstream);

int i = readHeader();

fields = new JDBField[i];

int j = 1;

for (int k = 0; k < i; k++) {

fields[k] = readFieldHeader();

j += fields[k].getLength();

}

if (stream.read() < 1)

throw new JDBFException("Unexpected end of file reached.");

nextRecord = new byte[j];

try {

stream.readFully(nextRecord);

} catch (EOFException eofexception) {

nextRecord = null;

stream.close();

}

} catch (IOException ioexception) {

throw new JDBFException(ioexception);

}

}

private int readHeader() throws IOException, JDBFException {

byte abyte0[] = new byte[16];

try {

stream.readFully(abyte0);

}

catch (EOFException eofexception) {

throw new JDBFException("Unexpected end of file reached.");

}

int i = abyte0[8];

if (i < 0)

i += 256;

i += 256 * abyte0[9];

i = --i / 32;

i--;

try {

stream.readFully(abyte0);

}

catch (EOFException eofexception1) {

throw new JDBFException("Unexpected end of file reached.");

}

return i;

}

private JDBField readFieldHeader() throws IOException, JDBFException {

byte abyte0[] = new byte[16];

try {

stream.readFully(abyte0);

}

catch (EOFException eofexception) {

throw new JDBFException("Unexpected end of file reached.");

}

StringBuffer stringbuffer = new StringBuffer(10);

for (int i = 0; i < 10; i++) {

if (abyte0[i] == 0)

break;

stringbuffer.append( (char) abyte0[i]);

}

char c = (char) abyte0[11];

try {

stream.readFully(abyte0);

}

catch (EOFException eofexception1) {

throw new JDBFException("Unexpected end of file reached.");

}

int j = abyte0[0];

int k = abyte0[1];

if (j < 0)

j += 256;

if (k < 0)

k += 256;

return new JDBField(stringbuffer.toString(), c, j, k);

}

public int getFieldCount() {

return fields.length;

}

public JDBField getField(int i) {

return fields[i];

}

public boolean hasNextRecord() {

return nextRecord != null;

}

public Object[] nextRecord() throws JDBFException {

if (!hasNextRecord())

throw new JDBFException("No more records available.");

Object aobj[] = new Object[fields.length];

int i = 1;

for (int j = 0; j < aobj.length; j++) {

int k = fields[j].getLength();

StringBuffer stringbuffer = new StringBuffer(k);

stringbuffer.append(new String(nextRecord, i, k));

aobj[j] = fields[j].parse(stringbuffer.toString());

i += fields[j].getLength();

}

try {

stream.readFully(nextRecord);

}

catch (EOFException eofexception) {

nextRecord = null;

}

catch (IOException ioexception) {

throw new JDBFException(ioexception);

}

return aobj;

}

public void close() throws JDBFException {

nextRecord = null;

try {

stream.close();

}

catch (IOException ioexception) {

throw new JDBFException(ioexception);

}

}

private DataInputStream stream;

private JDBField fields[];

private byte nextRecord[];

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值