用javaDBF操作(读、写)DBF文件
http://www.iteye.com/topic/106065
下面是分别是读取和写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中的字段类型表示应该是不一致的,这里做一个类型映射和转换即可。
下面是封装好的一个读写DBF文件的工具类(仅供参考):
/** * Copyright (C) 2009 numenzq studio. All Rights Reserved. */ package com.linkstec.mot.job.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.apache.commons.beanutils.PropertyUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.linuxense.javadbf.DBFField; import com.linuxense.javadbf.DBFReader; import com.linuxense.javadbf.DBFWriter; /** * DBF 文件解析 * */ public class DbfUtil { private final static String CHARSET = "GB2312"; /** * 读DBF文件 * @param file * @param clazz * @param template * @return * @throws DocumentException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws IOException */ public static <T> List<T> readDbf(File file, Class<T> clazz, InputStream template) throws DocumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { FileInputStream fis = new FileInputStream(file); DBFReader reader = new DBFReader(fis); reader.setCharactersetName(CHARSET); List<Element> propertys = readTemplate(template); for(Element element : propertys){ int fieldsCount = reader.getFieldCount(); for (int i = 0; i < fieldsCount; i++) { DBFField field = reader.getField(i); if(field.getName().equals(element.attributeValue("column"))){ element.addAttribute("index", i+""); break; } } } List<T> records = new ArrayList<T>(); for (int i = 0; i < reader.getRecordCount(); i++) { // System.out.println(i+1 + "/" + reader.getRecordCount()); records.add(readLine(clazz, propertys, reader.nextRecord())); } fis.close(); return records; } /** * 写DBF文件 * @param beans * @param template * @return * @throws DocumentException * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws IOException */ public static byte[] writeDbf(List<? extends Object> beans, InputStream template) throws DocumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { List<Element> propertys = readTemplate(template); DBFWriter writer = new DBFWriter(); writer.setCharactersetName(CHARSET); writer.setFields(writeFields(propertys)); for (int i = 0; i < beans.size(); i++) { writer.addRecord(writeLine(beans.get(i), propertys)); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); writer.write(baos); return baos.toByteArray(); } /** * 写DBF文件(方式2) * @param beans * @param template * @param file * @throws DocumentException * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws IOException */ public static void writeDbf(List<? extends Object> beans, InputStream template,File file) throws DocumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { List<Element> propertys = readTemplate(template); DBFWriter writer = new DBFWriter(file); writer.setCharactersetName(CHARSET); writer.setFields(writeFields(propertys)); for (int i = 0; i < beans.size(); i++) { writer.addRecord(writeLine(beans.get(i), propertys)); } writer.write(); } /** * SAX解析表结构模板 * @param in * @return * @throws DocumentException */ @SuppressWarnings("unchecked") private static List<Element> readTemplate(InputStream in) throws DocumentException { SAXReader reader = new SAXReader(); Document document = reader.read(in); return (List<Element>)document.getRootElement().elements(); } /** * 读取一行数据 * @param clazz * @param propertys * @param values * @return * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException */ private static <T> T readLine(Class<T> clazz, List<Element> propertys, Object[] values) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { T bean = clazz.newInstance(); for (int i = 0; i < propertys.size(); i++) { Element property = propertys.get(i); if(property.attributeValue("index") != null && property.attributeValue("index").length() > 0){ int index = Integer.parseInt(property.attributeValue("index")); Object value = values[index]; if (property.attributeValue("type").equals("C")) { value = ((String) value).trim(); }else if (property.attributeValue("type").equals("N")) { // if (property.attributeValue("scale")!=null && !"".equals(property.attributeValue("scale"))) { value = new BigDecimal(((Double) value).doubleValue()); // }else{ // value = ((Double) value).longValue(); // } } // BeanUtil.copyProperty(bean, property.attributeValue("name"), value); PropertyUtils.setProperty(bean, property.attributeValue("name"), value); } } return bean; } /** * 写一行数据 * @param bean * @param propertys * @return * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException */ private static Object[] writeLine(Object bean, List<Element> propertys) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Object[] row = new Object[propertys.size()]; for (int i = 0; i < propertys.size(); i++) { Element element = propertys.get(i); row[i] = PropertyUtils.getProperty(bean, element.attributeValue("name")); } return row; } /** * 设置表结构 * @param propertys * @return */ private static DBFField[] writeFields(List<Element> propertys) { DBFField[] fields = new DBFField[propertys.size()]; for (int i = 0; i < propertys.size(); i++) { Element property = propertys.get(i); fields[i] = new DBFField(); fields[i].setName(property.attributeValue("column")); fields[i].setDataType((byte) property.attributeValue("type").charAt(0)); if (property.attributeValue("length") != null) { fields[i].setFieldLength(Integer.parseInt(property.attributeValue("length"))); } if (property.attributeValue("scale") != null) { fields[i].setDecimalCount(Integer.parseInt(property.attributeValue("scale"))); } } return fields; } }
表结构模板实例:
<?xml version="1.0" encoding="UTF-8"?> <dbf-template class="com.linkstec.msp.credit.dto.CI10S03Dto" description="客户风险测评"> <property title="营业部名称" name="yybmc" column="yybmc" type="C" length="30" /> <property title="营业部编号" name="yybid" column="yybid" type="C" length="10" /> <property title="客户名称" name="khmc" column="khmc" type="C" length="10" /> <property title="客户编号" name="khid" column="khid" type="C" length="10" /> <property title="测评开始日期" name="startDate" column="startDate" type="D" /> <property title="测评到期日期" name="endDate" column="endDate" type="D" /> <property title="测评得分" name="cpdf" column="cpdf" type="C" length="10" /> <property title="测评方式" name="cpfs" column="cpfs" type="C" length="10" /> </dbf-template>