JAVA操作dbf文件的读写,这里使用第三方API:javadbf
<!-- javadbf --> <dependency> <groupId>com.github.albfernandez</groupId> <artifactId>javadbf</artifactId> <version>1.9.2</version> </dependency>
[XBase类型] | [XBase符号] | [JavaDBF中java类型] |
---|---|---|
Character | C | java.lang.String |
Numeric | N | java.math.BigDecimal |
Double | F | java.math.BigDecimal |
Logical | L | java.lang.Boolean |
Date | D | java.util.Date |
这算是javadbf的待完善之处,后续版本有可能会跟进优化
[FoxPro类型] | [符号] | [JavaDBF中java类型] |
---|---|---|
Currency | Y | java.math.BigDecimal |
Long | I | java.lang.Integer |
Date Type | T | java.util.Date |
Timestamp | @ | java.util.Date |
AutoIncrement | + | java.lang.Integer |
Memo | M | java.lang.String or byte[] |
Binary | B | byte[] or java.lang.Double |
Blob | W | byte[] |
General | G | byte[] |
Picture | P | byte[] |
VarBinary | Q | byte[] |
Varchar | V | java.lang.String |
Double | O | java.lang.Double |
表: 对应一个 dbf文件,库与表一个概念 表关联: 表之间没有关联查询的功能 创建表: 创建文件,创建列,参考[testWrite1-见下方] 删除表: 删除文件即可 索引: 没有索引概念 增: 第一次创建文件,或者,一次性将数据覆盖原有文件,参考[testWrite1-见下方] 在文件末尾添加记录,参考[testWrite2-见下方] 删: 在[遍历表]的基础上,将想删的数据过滤,再覆盖文件 改: 在[遍历表]的基础上,将想改的数据修改,再覆盖文件 查: [遍历表] 逐条记录读取,记录转Object数组,参考[testRead1-见下方] 逐条记录读取,根据列名读取列,参考[testRead2-见下方] 根据条件查 在遍历表的基础上,读取列,判断条件
/** * dbf文件 */ public static final String DBF_FILE = "/Users/guanxianghui/Desktop/user.dbf"; /** * 测试读取文件-逐条记录读取,记录转Object数组 */ @Test public void testRead1() { System.out.println("[测试读取文件-逐条记录读取,记录转Object数组]"); System.out.println("DBF文件路径:[" + DBF_FILE + "]"); DBFReader reader = null; try { /** * 读工具类,指定文件 */ reader = new DBFReader(new FileInputStream(DBF_FILE), Charset.forName("GBK")); /** * 读取表结构 */ int numberOfFields = reader.getFieldCount(); System.out.println("表结构共:[" + numberOfFields + "]列"); System.out.println("========="); for (int i = 0; i < numberOfFields; i++) { DBFField field = reader.getField(i); System.out.println("列:" + field.getName() + "[" + field.getLength() + "]"); } System.out.println("========="); /** * 逐条记录读取,记录转Object数组 */ System.out.println("总记录数[" + reader.getRecordCount() + "],逐条记录读取,记录转Object数组"); System.out.println("========="); Object[] rowObjects; int index = 0; while (null != (rowObjects = reader.nextRecord())) { String content = ""; for (int i = 0; i < rowObjects.length; i++) { if (StringUtils.isNotBlank(content)) { content += ","; } content += rowObjects[i] + "[" + rowObjects[i].getClass().getName() + "]"; } System.out.println("记录[" + (++index) + "]:" + content); } System.out.println("========="); } catch (DBFException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { /** * 关闭资源 */ if (null != reader) { DBFUtils.close(reader); } } }
输出
[测试读取文件-逐条记录读取,记录转Object数组] DBF文件路径:[/Users/guanxianghui/Desktop/user.dbf] 表结构共:[3]列 ========= 列:COUNTRY[10] 列:NAME[20] 列:SALARY[12] ========= 总记录数[3],逐条记录读取,记录转Object数组 ========= 记录[1]:中国[java.lang.String],关向辉[java.lang.String],5000.01[java.math.BigDecimal] 记录[2]:英国[java.lang.String],关向新[java.lang.String],3400.20[java.math.BigDecimal] 记录[3]:澳门[java.lang.String],关向阳[java.lang.String],7300.03[java.math.BigDecimal] =========
/** * dbf文件 */ public static final String DBF_FILE = "/Users/guanxianghui/Desktop/user.dbf"; /** * 测试读取文件-逐条记录读取,根据列名读取列 */ @Test public void testRead2() { System.out.println("[测试读取文件-逐条记录读取,根据列名读取列]"); System.out.println("DBF文件路径:[" + DBF_FILE + "]"); DBFReader reader = null; try { /** * 读工具类,指定文件 */ reader = new DBFReader(new FileInputStream(DBF_FILE), Charset.forName("GBK")); /** * 读取表结构 */ int numberOfFields = reader.getFieldCount(); System.out.println("表结构共[:" + numberOfFields + "]列"); System.out.println("========="); for (int i = 0; i < numberOfFields; i++) { DBFField field = reader.getField(i); System.out.println("列:" + field.getName() + "[" + field.getLength() + "]"); } System.out.println("========="); System.out.println("总记录数[" + reader.getRecordCount() + "],逐条记录读取,根据列名读取列"); System.out.println("========="); /** * 逐条记录读取,根据列名读取列 */ DBFRow row; int index = 0; while ((row = reader.nextRow()) != null) { System.out.println("第[" + (++index) + "]记录,COUNTRY:[" + row.getString("COUNTRY") + "],NAME:[" + row.getString("NAME") + "],SALARY:[" + row.getString("SALARY") + "]"); } System.out.println("========="); } catch (DBFException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { /** * 关闭资源 */ if (null != reader) { DBFUtils.close(reader); } } }
输出
[测试读取文件-逐条记录读取,根据列名读取列] DBF文件路径:[/Users/guanxianghui/Desktop/user.dbf] 表结构共[:3]列 ========= 列:COUNTRY[10] 列:NAME[20] 列:SALARY[12] ========= 总记录数[6],逐条记录读取,根据列名读取列 ========= 第[1]记录,COUNTRY:[中国],NAME:[关向辉],SALARY:[5000.01] 第[2]记录,COUNTRY:[英国],NAME:[关向新],SALARY:[3400.20] 第[3]记录,COUNTRY:[澳门],NAME:[关向阳],SALARY:[7300.03] 第[4]记录,COUNTRY:[中国],NAME:[关向辉],SALARY:[5000.01] 第[5]记录,COUNTRY:[英国],NAME:[关向新],SALARY:[3400.20] 第[6]记录,COUNTRY:[澳门],NAME:[关向阳],SALARY:[7300.03] =========
这种方式是正常(Normal)模式(Mode),即非(Not)同步(Syn)方式(Mode),所有数据储存在内存中,在关闭(Close)资源时一口气输出到dfb文件,覆盖文件列+数据!好处:交互少,性能高,在数据量小的场景适用!隐患:数据量过大,有可能会导致内存溢出!
/** * dbf文件 */ public static final String DBF_FILE = "/Users/guanxianghui/Desktop/user.dbf"; /** * 测试写文件-FileOutputStream-覆盖文件列+数据 */ @Test public void testWrite1() { System.out.println("[测试写文件-FileOutputStream-覆盖文件列+数据]"); System.out.println("DBF文件路径:[" + DBF_FILE + "]"); /** * 定义列 */ DBFField[] fields = new DBFField[3]; fields[0] = new DBFField(); fields[0].setName("COUNTRY"); fields[0].setType(DBFDataType.CHARACTER); fields[0].setLength(10); fields[1] = new DBFField(); fields[1].setName("NAME"); fields[1].setType(DBFDataType.CHARACTER); fields[1].setLength(20); fields[2] = new DBFField(); fields[2].setName("SALARY"); fields[2].setType(DBFDataType.NUMERIC); fields[2].setLength(12); fields[2].setDecimalCount(2); DBFWriter writer = null; System.out.println("设置列,并输出数据到文件"); System.out.println("========="); try { /** * 输出到文件 */ writer = new DBFWriter(new FileOutputStream(DBF_FILE), Charset.forName("GBK"));//注意,是FileOutputStream /** * 设置列 */ for (DBFField field : fields) { System.out.println("列:" + field.getName() + "[" + field.getLength() + "]"); } writer.setFields(fields); System.out.println("========="); /** * 设置数据,并新增数据 */ Object rowData[] = new Object[3]; rowData[0] = "中国"; rowData[1] = "关向辉"; rowData[2] = new Double(5000.01); System.out.println("输出数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); rowData = new Object[3]; rowData[0] = "英国"; rowData[1] = "关向新"; rowData[2] = new Double(3400.20); System.out.println("输出数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); rowData = new Object[3]; rowData[0] = "澳门"; rowData[1] = "关向阳"; rowData[2] = new Double(7300.03); System.out.println("输出数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { /** * 关闭资源 */ if (null != writer) { DBFUtils.close(writer); } } System.out.println("========="); System.out.println("输出完成"); }
输出
[测试写文件-FileOutputStream-覆盖文件列+数据] DBF文件路径:[/Users/guanxianghui/Desktop/user.dbf] 设置列,并输出数据到文件 ========= 列:COUNTRY[10] 列:NAME[20] 列:SALARY[12] ========= 输出数据:[中国,关向辉,5000.01] 输出数据:[英国,关向新,3400.2] 输出数据:[澳门,关向阳,7300.03] ========= 输出完成
这种方式是同步(Syn)方式(Mode),添加记录addRecord方法调用时,马上输出到dfb文件!好处:数据量大时候,不会内存溢出!隐患:交互多,数据量小的场景,性能低下!
同步(Syn)方式(Mode),如果dbf文件存在,而且已经有列定义,不能重复操作列定义(重复操作会报错:com.linuxense.javadbf.DBFException: Fields has already been set),如果dbf是新文件,则可以操作一次列定义。
/** * dbf文件 */ public static final String DBF_FILE = "/Users/guanxianghui/Desktop/user.dbf"; /** * 测试写文件-File-文件列不变,append追加数据 */ @Test public void testWrite2() { System.out.println("[测试写文件-File-文件列不变,append追加数据]"); System.out.println("DBF文件路径:[" + DBF_FILE + "]"); DBFWriter writer = null; System.out.println("========="); try { /** * 输出到文件 */ writer = new DBFWriter(new File(DBF_FILE), Charset.forName("GBK"));//注意,是File /** * 设置数据,并新增数据 */ Object rowData[] = new Object[3]; rowData[0] = "中国"; rowData[1] = "关向辉"; rowData[2] = new Double(5000.01); System.out.println("追加数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); rowData = new Object[3]; rowData[0] = "英国"; rowData[1] = "关向新"; rowData[2] = new Double(3400.20); System.out.println("追加数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); rowData = new Object[3]; rowData[0] = "澳门"; rowData[1] = "关向阳"; rowData[2] = new Double(7300.03); System.out.println("追加数据:[" + rowData[0] + "," + rowData[1] + "," + rowData[2] + "]"); writer.addRecord(rowData); } finally { /** * 关闭资源 */ if (null != writer) { DBFUtils.close(writer); } } System.out.println("========="); System.out.println("输出完成"); }
输出
[测试写文件-File-文件列不变,append追加数据] DBF文件路径:[/Users/guanxianghui/Desktop/user.dbf] ========= 追加数据:[中国,关向辉,5000.01] 追加数据:[英国,关向新,3400.2] 追加数据:[澳门,关向阳,7300.03] ========= 输出完成
可以解压zip得到dbf示例文件 user.dbf.zip