.net(c#)读取*.dbf文件数据的类库

新制作了一个库存管理软件(c/s),数据库用mssql,客户端用.net开发。

用户在客户端对数据进行查看、添加、导入、编辑、删除、打印等操作。

公司原来的一些数据存储在.dbf文件中,必须在客户端对.dbf文件进行访问,以导入数据。

从网上搜集到关于.dbf文件格式的信息和一部分c语言直接访问.dbf文件的实例,写了一个c#直接访问.dbf的类,支持直接获取.dbf文件的DataSet,获取单个字段信息等。

1。定义.dbf文件头类


namespace  Sunman.DBF
{
    
using System;

    
/// <summary>
    
/// .dbf 文件的文件头信息类
    
/// </summary>

    internal class DBFHeader
    
{
        
public const int DBFHeaderSize = 32;
        
/* 版本标志
                     0x02    FoxBASE  
                    0x03    FoxBASE+/dBASE III PLUS,无备注  
                    0x30    Visual FoxPro  
                    0x43    dBASE IV SQL 表文件,无备注  
                    0x63    dBASE IV SQL 系统文件,无备注  
                    0x83    FoxBASE+/dBASE III PLUS,有备注  
                    0x8B    dBASE IV 有备注  
                    0xCB    dBASE IV SQL 表文件,有备注  
                    0xF5    FoxPro 2.x(或更早版本)有备注  
                    0xFB    FoxBASE  
        
*/

        
public sbyte Version;
        
/* 最后更新年 */ 
        
public byte LastModifyYear;
        
/* 最后更新月 */
        
public byte LastModifyMonth;
        
/* 最后更新日 */
        
public byte LastModifyDay;
        
/* 文件包含的总记录数 */ 
        
public uint RecordCount;
        
/* 第一条记录的偏移值,这个值也可以表示文件头长度 */ 
        
public ushort HeaderLength;
        
/* 记录长度,包括删除标志*/
        
public ushort RecordLength;
        
/* 保留 */ 
        
public byte[] Reserved = new byte[16];
        
/* 表的标志
                     0x01具有 .cdx 结构的文件
                    0x02文件包含备注
                    0x04文件是数据库(.dbc) 
                    标志可OR 
        
*/

        
public sbyte TableFlag;
        
/* 代码页标志 */
        
public sbyte CodePageFlag;
        
/* 保留 */
        
public byte[] Reserved2 = new byte[2];
    }

}

2。定义.dbf文件字段信息类。


namespace  Sunman.DBF
{
    
using System;

    
/// <summary>
    
/// .dbf 文件的字段信息类
    
/// </summary>

    internal class DBFField
    
{
        
public const int DBFFieldSize = 32;
        
/* 字段名称 */ 
        
public byte[] Name = new byte[11];
        
/* 字段类型 C - 字符型  
                    Y - 货币型  
                    N - 数值型  
                    F - 浮点型  
                    D - 日期型  
                    T - 日期时间型  
                    B - 双精度型  
                    I - 整型  
                    L - 逻辑型 
                    M - 备注型  
                    G - 通用型  
                    C - 字符型(二进制) 
                    M - 备注型(二进制) 
                    P - 图片型  
        
*/
 
        
public sbyte Type;
        
/* 字段偏移量 */
        
public uint Offset;
        
/* 字段长度 */ 
        
public byte Length;
        
/* 浮点数小数部分长度 */ 
        
public byte Precision;
        
/* 保留 */ 
        
public byte[] Reserved = new byte[2];
        
/* dBASE IV work area id */ 
        
public sbyte DbaseivID;
        
/* */
        
public byte[] Reserved2 = new byte[10];
        
/* */
        
public sbyte ProductionIndex;
    }

}

3。.dbf文件访问类。使用System.IO.BinaryReader类来读取.dbf文件的二进制数据,然后根据不同的字段类型和数据在.dbf文件里的存储格式对读取到的二进制数据进行解码操作。

(1)。Numeric、float、char型的数据都是明文存储,也只要江二进制数据转换为对应的字符串形式然后转换为相应的数据类型即可。

(2)。Integer型:32位。存储的就是integer类型数据的内存格式,将各个字节的数据移位然后或上即可。

(3)。Double型:64位,不定精度。应该也是double类型数据的内存格式,由于小数位数不确定,使用指针直接获取内存信息。

(4)。Currency型:64位,精度很重要(明确为4位)。读取到的数据.net中用Decimal类型存储。.dbf文件中存储的应该是Currency数据放大10000倍后的long类型数据的内存格式,所以现将文件中的二进制数据读取为对应的int64类型数据,然后缩小10000倍就行。

(5)。Date型:64位。存储的也是明文,前32位为带世纪的年度,后16位为日,剩下的16位为月。

(6)。DateTime型:64位。存储格式与Date型差异就大了。我认为前32位存储的是日期相对于某一日(还没弄清楚是那一日,只是离1年1月1日有1721426天的差距),后32位存储的是时间部分的毫秒数,我就分日期部分和时间部分读取。将日期部分读取为int32数据的天数,减去1721426后,增加到1年1月1日,得到日期部分;读取时间部分的数据为int32的毫秒数,增加到前面获取到的日期上,得到完整的日期。

获取到字段数据后,再对数据进行排错处理。这个主要是针对.dbf中numeric型和float型数据可以只存在空格和"."的现象和boolean型数据存储的是“T”和“F”。

代码如下:


namespace  Sunman.DBF
{
    
using System;
    
using System.IO;

    
/// <summary>
    
/// .dbf文件操作类
    
/// </summary>

    public class DBFFile : IDisposable
    
{
        
private const string MSG_OPEN_FILE_FAIL = "不能打开文件{0}";

        
private bool _isFileOpened;
        
private byte[] _recordBuffer;
        
private DBFField[] _dbfFields;
        
private System.IO.FileStream _fileStream = null;
        
private System.IO.BinaryReader _binaryReader = null;
        
private string _fileName = string.Empty;
        
private uint _fieldCount = 0;
        
private int _recordIndex = -1;
        
private uint _recordCount = 0;
        
private DBFHeader _dbfHeader = null;

        
/// <summary>
        
/// 构造函数
        
/// </summary>

        public DBFFile()
        
{
        }


        
/// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="fileName"></param>

        public DBFFile(string fileName)
        
{
            
if (null != fileName && 0 != fileName.Length)
                
this._fileName = fileName;
        }


        
/// <summary>
        
/// 清理所有正在使用的资源。
        
/// </summary>

        protected virtual void Dispose( bool disposing )
        
{
            
if( disposing )
            
{
                
this._recordBuffer = null;
                
this._dbfHeader = null;
                
this._dbfFields = null;
            
                
if (this.IsFileOpened && null != this._fileStream)
                
{
                    
this._fileStream.Close();
                    
this._binaryReader.Close();
                }

                
this._fileStream = null;
                
this._binaryReader = null;

                
this._isFileOpened = false;
                
this._fieldCount = 0;
                
this._recordCount = 0;
                
this._recordIndex = -1;
            }

        }


        
/// <summary>
        
/// 打开dbf文件
        
/// </summary>
        
/// <returns></returns>

        public bool Open()
        
{
            
try
            
{
                
return this.Open(null);
            }

            
catch (Exception e)
            
{
                
throw e;
            }

        }


        
/// <summary>
        
/// 打开dbf文件
        
/// </summary>
        
/// <param name="fileName"></param>
        
/// <returns></returns>

        public bool Open(string fileName)
        
{        
            
if (null != fileName)
                
this._fileName = fileName;

            
bool ret = false;

            
try
            
{
                
if (!this.OpenFile())
                
{
                    
// 不能打开dbf文件,抛出不能打开文件异常
                    throw new Exception(string.Format(MSG_OPEN_FILE_FAIL, this._fileName));
                }


                
// 读取文件头信息
                ret = this.ReadFileHeader();

                
// 读取所有字段信息
                if (ret)
                    ret 
= this.ReadFields();

                
// 分配记录缓冲区
                if (ret && null == this._recordBuffer)
                
{
                    
this._recordBuffer = new byte[this._dbfHeader.RecordLength];

                    
if (null == this._recordBuffer)
                        ret 
= false;
                }


                
// 如果打开文件或读取信息不成功,关闭dbf文件
                if (!ret)
                    
this.Close();
            }

            
catch (Exception e)
            
{
                
throw e;
            }


            
// 设置当前记录索引为
            this._recordIndex = -1;

            
// 返回打开文件并且读取信息的成功状态
            return ret;
        }
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuxi81

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值