设为首页 加入收藏

TOP

TinyDBF-200行写个DBF解析器(一)
2014-11-24 00:38:23 来源: 作者: 【 】 浏览:26
Tags:TinyDBF-200 DBF 解析

序言

由于工作关系,需要工作当中,需要读取DBF文件,找了一些DBF读取开源软件,要么是太过庞大,动不动就上万行,要么是功能有问题,编码,长度,总之是没有找到一个非常爽的。在万般无奈之下,我老人家怒从心头起,恶向胆边生,决定自己写一下。结果只用了不到300行代码就搞定了,当然搞定不是唯一目标,还要优雅简洁的搞定,亲们跟随我的脚步一起感受一下简洁的设计与实现吧。

在开始编码之前,先介绍一下DBF,这个DBF可是个老东西,在DOS时代就已经出现,并且风骚了相当一段时间,后来随着大型数据库的应用,它逐步没落,但是由于其简洁易用的特点,还是应用在大量的数据交换当中。但是其发展过程中,也形成了许多种版本,不同版本的结构不一样,也就决定 了其解析程序也是不一样的。

今天我只实现了Foxbase/DBaseIII的解析,但是也为扩展各种其它版本做好了准备。

接口设计

\

上面一共就两个类,一个接口,Field和Header就是两个简单的POJO类,分别定义了文件头及字段相关的信息。

Reader接口是DBF文件读取的接口,主要定义了获取文件类型,编码,字段以及记录移动相关的方法。

代码实现

首先实现Reader的抽象类

public abstract class DbfReader implements Reader {
    protected String encode = "GBK";
    private FileChannel fileChannel;
    protected Header header;
    protected List fields;
    private boolean recordRemoved;
    int position = 0;
    static Map readerMap = new HashMap();

    static {
        addReader(3, FoxproDBase3Reader.class);
    }

    public static void addReader(int type, Class clazz) {
        readerMap.put(type, clazz);
    }

    public static void addReader(int type, String className) throws ClassNotFoundException {
        readerMap.put(type, Class.forName(className));
    }

    public byte getType() {
        return 3;
    }

    public String getEncode() {
        return encode;
    }

    public Header getHeader() {
        return header;
    }

    public List getFields() {
        return fields;
    }


    public boolean isRecordRemoved() {
        return recordRemoved;
    }

    public static Reader parse(String dbfFile, String encode) throws IOException, IllegalAccessException, InstantiationException {
        return parse(new File(dbfFile), encode);
    }

    public static Reader parse(String dbfFile) throws IOException, IllegalAccessException, InstantiationException {
        return parse(new File(dbfFile), "GBK");
    }

    public static Reader parse(File dbfFile) throws IOException, IllegalAccessException, InstantiationException {
        return parse(dbfFile, "GBK");
    }

    public static Reader parse(File dbfFile, String encode) throws IOException, IllegalAccessException, InstantiationException {
        RandomAccessFile aFile = new RandomAccessFile(dbfFile, "r");
        FileChannel fileChannel = aFile.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1);
        fileChannel.read(byteBuffer);
        byte type = byteBuffer.array()[0];
        Class readerClass = readerMap.get((int) type);
        if (readerClass == null) {
            fileChannel.close();
            throw new IOException("不支持的文件类型[" + type + "]。");
        }
        DbfReader reader = (DbfReader) readerClass.newInstance();
        reader.setFileChannel(fileChannel);
        reader.readHeader();
        reader.readFields();
        return reader;
    }

    public void setFileChannel(FileChannel fileChannel) {
        this.fileChannel = fileChannel;
    }


    protected abstract void readFields() throws IOException;

    public void moveBeforeFirst() throws IOException {
        position = 0;
        fileChannel.position(header.getHeaderLength());
    }

    /**
     * @param position 从1开始
     * @throws java.io.IOException
     */
    public void absolute(int position) throws IOException {
        checkPosition(position);
        this.position = position;
        fileChannel.position(header.getHeaderLength() + (position - 1) * header.getRecordLength());
    }

    private void checkPosition(int position) throws IOException {
        if (position >= header.getRecordCount()) {
            throw new IOException("期望记录行数为" + (this.position + 1) + ",超过实际记录行数:" + header.getRecor
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇PostgreSQL数据库远程连接功能的.. 下一篇Linux-6.5下基于MariaDB-10的主从..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: