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>
