用JavaDBF操作(读、写)DBF文件

最近的一个项目需要动态生成DBF文件,用到JavaDBF,简单介绍一下

官方网站:http://javadbf.sarovar.org/

官方英文指南:http://sarovar.org/docman/view.php/32/23/javadbf-tutorial.html

最新版本:0.4.0,最后发布时间还是在2004年4月1日,看来DBF真是老了。老归老,有些时候还是得用。

下面是分别是读取和写DBF文件以及其他操作函数(关键信息的解释我放在了注释里,这样看起来会更方便):

读取DBF文件:

package dbf;

import java.io.FileInputStream;
import java.io.InputStream;

import com.linuxense.javadbf.DBFField;
import com.linuxense.javadbf.DBFReader;

public class readDBF {
	public static void readDBF(String path) {
		InputStream fis = null;
		try {
			// 读取文件的输入流
			fis = new FileInputStream(path);
			// 根据输入流初始化一个DBFReader实例,用来读取DBF文件信息
			DBFReader reader = new DBFReader(fis);
			// 调用DBFReader对实例方法得到path文件中字段的个数
			int fieldsCount = reader.getFieldCount();
			// 取出字段信息
			for (int i = 0; i < fieldsCount; i++) {
				DBFField field = reader.getField(i);
				System.out.println(field.getName());
			}
			Object[] rowValues;
			// 一条条取出path文件中记录
			while ((rowValues = reader.nextRecord()) != null) {
				for (int i = 0; i < rowValues.length; i++) {
					System.out.println(rowValues[i]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fis.close();
			} catch (Exception e) {
			}
		}
	}
	
	public static void main(String[] args) {
		readDBF.readDBF("c:/到货明细表.DBF");
	}
}



写DBF文件:

package dbf;

import java.io.FileOutputStream;
import java.io.OutputStream;

import com.linuxense.javadbf.DBFField;
import com.linuxense.javadbf.DBFWriter;

public class writeDBF {
	public static void writeDBF(String path) {
		OutputStream fos = null;
		try {
			// 定义DBF文件字段
			DBFField[] fields = new DBFField[3];
			// 分别定义各个字段信息,setFieldName和setName作用相同,
			// 只是setFieldName已经不建议使用
			fields[0] = new DBFField();
			// fields[0].setFieldName("emp_code");
			fields[0].setName("semp_code");
			fields[0].setDataType(DBFField.FIELD_TYPE_C);
			fields[0].setFieldLength(10);
			fields[1] = new DBFField();
			// fields[1].setFieldName("emp_name");
			fields[1].setName("emp_name");
			fields[1].setDataType(DBFField.FIELD_TYPE_C);
			fields[1].setFieldLength(20);
			fields[2] = new DBFField();
			// fields[2].setFieldName("salary");
			fields[2].setName("salary");
			fields[2].setDataType(DBFField.FIELD_TYPE_N);
			fields[2].setFieldLength(12);
			fields[2].setDecimalCount(2);
			// DBFWriter writer = new DBFWriter(new File(path));
			// 定义DBFWriter实例用来写DBF文件
			DBFWriter writer = new DBFWriter();
			// 把字段信息写入DBFWriter实例,即定义表结构
			writer.setFields(fields);
			// 一条条的写入记录
			Object[] rowData = new Object[3];
			rowData[0] = "1000";
			rowData[1] = "John";
			rowData[2] = new Double(5000.00);
			writer.addRecord(rowData);
			rowData = new Object[3];
			rowData[0] = "1001";
			rowData[1] = "Lalit";
			rowData[2] = new Double(3400.00);
			writer.addRecord(rowData);
			rowData = new Object[3];
			rowData[0] = "1002";
			rowData[1] = "Rohit";
			rowData[2] = new Double(7350.00);
			writer.addRecord(rowData);
			// 定义输出流,并关联的一个文件
			fos = new FileOutputStream(path);
			// 写入数据
			writer.write(fos);
			// writer.write();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fos.close();
			} catch (Exception e) {
			}
		}
	}
}



注意:writer.addRecord(rowData)时并不真正写入数据,在最后writer.write(fos)时才会把数据写入DBF文件,之前addRecord的数据暂时存放在内存中。如果数据量过大,这种方式显然不适合,内存中存储的数据过多,所以JavaDBF提供了另外一种机制来解决这个问题:Sync Mode(同步模式)。使用方法如下:

用new DBFWriter(new File(path))实例化DBFWriter类,最后写入数据时用writer.write(),这样在每次addRecord时数据就被写入的DBF文件中。

因为初始化DBFWriter时传递了DBF文件,所以不用再定义DBF表结构,如果你定义并加载表结构会报异常。

下面这个函数会根据你传入的数据信息自动生成DBF文件,这样以后我们只要构造好数组,就可以直接得到DBF文件,不用每次都去写重复的代码。

package dbf;

import java.io.FileOutputStream;
import java.io.OutputStream;

import com.linuxense.javadbf.DBFField;
import com.linuxense.javadbf.DBFWriter;

public class Snippet {
	public static void generateDbfFromArray(String dbfName, String[] strutName,
			byte[] strutType, int[] strutLength, Object[][] data) {
		OutputStream fos = null;
		try {
			int fieldCount = strutName.length;
			DBFField[] fields = new DBFField[fieldCount];
			for (int i = 0; i < fieldCount; i++) {
				fields[i] = new DBFField();
				fields[i].setName(strutName[i]);
				fields[i].setDataType(strutType[i]);
				fields[i].setFieldLength(strutLength[i]);
			}
			DBFWriter writer = new DBFWriter();
			writer.setFields(fields);
			for (int i = 0; i < fieldCount; i++) {
				writer.addRecord(data[i]);
			}
			fos = new FileOutputStream(dbfName);
			writer.write(fos);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fos.close();
			} catch (Exception e) {
			}
		}

	}
}

可以看到定义JavaDBF表结构或者添加数据时是通过传递数组实现,也就是说只要我们有了这些用来构造表结果和表示结果集的数组就有了DBF文件,那么我们可以通过类似下面这样的函数把ResultSet信息转换成数组信息。


public static void ResultsetToArray(ResultSet rs) {
		try {
			ResultSetMetaData meta = rs.getMetaData();
			int columnCount = meta.getColumnCount();
			String[] strutName = new String[columnCount];
			byte[] strutType = new byte[columnCount];
			rs.last();
			int itemCount = rs.getRow();
			rs.first();
			Object[][] data = new Object[columnCount][itemCount];
			for (int i = 0; i < columnCount; i++) {
				strutType[i] = (byte) meta.getColumnType(i);
				strutName[i] = meta.getColumnName(i);
			}
			for (int i = 0; rs.next(); i++) {
				for (int j = 0; j < columnCount; j++) {
					data[i][j] = rs.getObject(j);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}



细心的读者可能会发现:strutType[i] = (byte)meta.getColumnType(i)这条语句是不可靠的,的却,这里的代码我省略了,JavaDBF中的字段类型表示和ResultSetMetaData中的字段类型表示应该是不一致的,这里做一个类型映射和转换即可。




JAR包在我的资源下载中