一个C#读取DBF文件的类TDbfTable

一个项目中必须使用C#读取比较老的DBF文件,并且不清楚该文件属于dBase或FoxPro的哪个版本。俺以前是通过VfpOdbc方式读取DBF记录(一般需要安装VfpOdbc驱动程序),但一直存在顾虑:Microsoft已经不支持VfpOdbc了,其最新的版本是1999年发布的6.*版,存在着与Win7/8的兼容性问题。于是,在网上查找了相关的代码,结果如下:CodeProject中的Pa
摘要由CSDN通过智能技术生成

    一个项目中必须使用C#读取比较老的DBF文件,并且不清楚该文件属于dBase或FoxPro的哪个版本。俺以前是通过VfpOdbc方式读取DBF记录(一般需要安装VfpOdbc驱动程序),但一直存在顾虑:Microsoft已经不支持VfpOdbc了,其最新的版本是1999年发布的6.*版,存在着与Win7/8的兼容性问题。于是,在网上查找了相关的代码,结果如下:

  1. CodeProject中的ParseDbf(地址)源代码:该代码存在一些问题,如:中文字段读取问题,中文记录值读取问题。关键的是,读俺项目中的DBF文件时报错,于是舍弃该代码;
  2. CSDN下载的ReadDbf.cs(地址源代码:该代码基本上能使用,但实际测试时还是发现了两个严重问题:1)修改DBF表结构后再读该文件报错误;2)没有考虑删除标志(读删除标志错误)。经过仔细分析源代码后解决了这两个问题。

    下面是整理重构ReadDbf.cs后的代码,可以读取DBF记录到一个DataTable中,使用方法:

  1. CSUST.Dbf.TDbfTable dbf = new CSUST.Dbf.TDbfTable(dbf文件名),其中dbf文件是含路径的全文件名
  2. dbf.Table即是获取的DataTable对象;
  3. dbf.DbfFields为DBF字段数组。

    重构时删除了部分注释,详细的解释说明请参考ReadDbf.cs中的代码。

    测试了二十多个DBF文件(Vfp2.5和Vfp6.0的DBF文件),通过与VfpOdbc读取的记录比较,TDbfTable读到的所有记录数据与VfpOdbc读取的一致,包括:字段类型、字段数、记录数、记录的各个字段值等,唯一不同的是一个记录的double值,在VfpOdbf读取的表中存在舍入误差。

    需要指出,ParseDbf、ReadDbf和本文介绍的TDbfTable均不能处理备注字段、二进制字段等情况。本着来源是开源的、重构后继续开源的原则发布代码如下,读者如果发现代码中的bug或有更好的解决方法,也请不吝指出。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace CSUST.Dbf
{
    #region TDbfTable更新历史
    //-----------------------------------------------------------------------------------------------
    // 1) 2013-06-10: (1) 自 ReadDbf.cs 移植过来
    //                (2) 读记录时, 首先读删除标志字节, 然后读记录. 原代码这个地方忽略了删除标志字节.
    //                (3) 原代码 MoveNext() 后没有再判是否文件尾, 在读修改结构后的表时报错误.
    // 2) 2013-06-11: (1) int.money.decimal.double 直接用 BitConverter 转换函数
    //                (2) Date类型转换时, 如果字符串为空, 则为1899-12-30日.
    //                (3) Time类型转换时, 如果天数和毫秒数全为0, 则为1899-12-30日.
    //                (4) Time类型转换时, 毫秒数存在误差, 有1000以下的整数数, 需要+1秒.
    //                (5) 读记录值时,  在定位首指针后, 顺序读每个记录数组.
    // 3) 2013-06-17  (1) 打开文件后需要关闭文件流, 增加一个 CloseFileStream() 方法
    // 4) 2013-06-18  (1) 把 CloseFileStream() 放到 try{}finally{} 结构中
    //-----------------------------------------------------------------------------------------------------
    #endregion

    public class TDbfHeader
    {
        public const int HeaderSize = 32;
        public sbyte Version;
        public byte LastModifyYear;
        public byte LastModifyMonth;
        public byte LastModifyDay;
        public int RecordCount;
        public ushort HeaderLength;
        public ushort RecordLength;
        public byte[] Reserved = new byte[16];
        public sbyte TableFlag;
        public sbyte CodePageFlag;
        public byte[] Reserved2 = new byte[2];
    }

    public class TDbfField
    {
        public const int FieldSize = 32;
        public byte[] NameBytes = new byte[11];  // 字段名称
        public byte TypeChar;
        public byte Length;
        public byte Precision;
        public byte[] Reserved = new byte[2];
        public sbyte DbaseivID;
        public byte[] Reserved2 = new byte[10];
        public sbyte ProductionIndex;

        public bool IsString
        {
            get
            {
                if (TypeChar == 'C')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsMoney
        {
            get
            {
                if(TypeChar == 'Y')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsNumber
        {
            get
            {
                if (TypeChar == 'N')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsFloat
        {
            get
            {
                if (TypeChar == 'F')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsDate
        {
            get
            {
                if (TypeChar == 'D')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsTime
        {
            get
            {
                if (TypeChar == 'T')
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsDouble
        {
            get
            {
                if (TypeChar == &
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值