C# 读取DBF文件到Datatable
此种方式不依赖与任何驱动,第三方插件。
核心代码TDbfTable如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data; namespace TestSCClearCard
{
#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 == 'B')
{
return true;
} return false;
}
} public bool IsInt {
get {
if (TypeChar == 'I')
{
return true;
} return false;
}
} public bool IsLogic {
get {
if (TypeChar == 'L')
{
return true;
} return false;
}
} public bool IsMemo {
get {
if (TypeChar == 'M')
{
return true;
} return false;
}
} public bool IsGeneral {
get {
if (TypeChar == 'G')
{
return true;
} return false;
}
} public Type FieldType {
get {
if (this.IsString == true)
{
return typeof(string);
}
else if (this.IsMoney == true || this.IsNumber == true || this.IsFloat == true)
{
return typeof(decimal);
}
else if (this.IsDate == true || this.IsTime == true)
{
return typeof(System.DateTime);
}
else if (this.IsDouble == true)
{
return typeof(double);
}
else if (this.IsInt == true)
{
return typeof(System.Int32);
}
else if (this.IsLogic == true)
{
return typeof(bool);
}
else if (this.IsMemo == true)
{
return typeof(string);
}
else if (this.IsMemo == true)
{
return typeof(string);
}
else
{
return typeof(string);
}
}
} public string GetFieldName()
{
return GetFieldName(System.Text.Encoding.Default);
} public string GetFieldName(System.Text.Encoding encoding)
{
string fieldName = encoding.GetString(NameBytes);
int i = fieldName.IndexOf('\0');
if (i > 0)
{
return fieldName.Substring(0, i).Trim();
} return fieldName.Trim();
}
} public class TDbfTable : IDisposable
{
private const byte DeletedFlag = 0x2A;
private DateTime NullDateTime = new DateTime(1899, 12, 30); // odbc中空日期对应的转换日期 private string _dbfFileName = null; private System.Text.Encoding _encoding = System.Text.Encoding.Default;
private System.IO.FileStream _fileStream = null;
private System.IO.BinaryReader _binaryReader = null; private bool _isFileOpened;
private byte[] _recordBuffer;
private int _fieldCount = 0; private TDbfHeader _dbfHeader = null;
private TDbfField[] _dbfFields;
private System.Data.DataTable _dbfTable = null; public TDbfTable(string fileName)
{
this._dbfFileName = fileName.Trim();
try
{
this.OpenDbfFile();
}
finally
{
this.CloseFileStream();
}
} public TDbfTable(string fileName, string encodingName)
{
this._dbfFileName = fileName.Trim();
this._encoding = GetEncoding(encodingName);
try
{
this.OpenDbfFile();
}
finally
{
this.CloseFileStream();
}
} void System.IDisposable.Dispose()
{
this.Dispose(true); // TODO: 添加 DBFFile.System.IDisposable.Dispose 实现
} protected virtual void Dispose(bool disposing)
{
if (disposing == true)
{
this.Close();
}
} private System.Text.Encoding GetEncoding(string encodingName)
{
if (string.IsNullOrEmpty(encodingName) == true)
{
return System.Text.Encoding.Default;
} if (encodingName.ToUpper() == "GB2313")
{
return System.Text.Encoding.GetEncoding("GB2312");
} if (encodingName.ToUpper() == "UNICODE")
{
return System.Text.Encoding.Unicode;
} if (encodingName.ToUpper() == "UTF8")
{
return System.Text.Encoding.UTF8;
} if (encodingName.ToUpper() == "UTF7")
{
return System.Text.Encoding.UTF7;
} if (encodingName.ToUpper() == "UTF32")
{
return System.Text.Encoding.UTF32;
} if (encodingName.ToUpper() == "ASCII")
{
return System.Text.Encoding.ASCII;
} return System.Text.Encoding.Default;
} public void Close()
{
this.CloseFileStream(); _recordBuffer = null;
_dbfHeader = null;
_dbfFields = null; _isFileOpened = false;
_fieldCount = 0;
} private void CloseFileStream()
{
if (_fileStream != null)
{
_fileStream.Close();
_fileStream = null;
} if (_binaryReader != null)
{
_binaryReader.Close();
_binaryReader = null;
}
} private void OpenDbfFile()
{
this.Close(); if (string.IsNullOrEmpty(_dbfFileName) == true)
{
throw new Exception("filename is empty or null.");
} if (System.IO.File.Exists(_dbfFileName) == false)
{
throw new Exception(this._dbfFileName + " does not exist.");
} try
{
this.GetFileStream();
this.ReadHeader();
this.ReadFields();
this.GetRecordBufferBytes();
this.CreateDbfTable();
this.GetDbfRecords();
}
catch (Exception e)
{
this.Close();
throw e;
}
} public void GetFileStream()
{
try
{
this._fileStream = File.Open(this._dbfFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
this._binaryReader = new BinaryReader(this._fileStream, _encoding);
this._isFileOpened = true;
}
catch
{
throw new Exception("fail to read " + this._dbfFileName + ".");
}
} private void ReadHeader()
{
this._dbfHeader = new TDbfHeader(); try
{
this._dbfHeader.Version = this._binaryReader.ReadSByte(); //第1字节
this._dbfHeader.LastModifyYear = this._binaryReader.ReadByte(); //第2字节
this._dbfHeader.LastModifyMonth = this._binaryReader.ReadByte(); //第3字节
this._dbfHeader.LastModifyDay = this._binaryReader.ReadByte(); //第4字节
this._dbfHeader.RecordCount = this._binaryReader.ReadInt32(); //第5-8字节
this._dbfHeader.HeaderLength = this._binaryReader.ReadUInt16(); //第9-10字节
this._dbfHeader.RecordLength = this._binaryReader.ReadUInt16(); //第11-12字节
this._dbfHeader.Reserved = this._binaryReader.ReadBytes(16); //第13-14字节
this._dbfHeader.TableFlag = this._binaryReader.ReadSByte(); //第15字节
this._dbfHeader.CodePageFlag = this._binaryReader.ReadSByte(); //第16字节
this._dbfHeader.Reserved2 = this._binaryReader.ReadBytes(2); //第17-18字节 this._fieldCount = GetFieldCount();
}
catch
{
throw new Exception("fail to read file header.");
}
} private int GetFieldCount()
{
// 由于有些dbf文件的文件头最后有附加区段,但是有些文件没有,在此使用笨方法计算字段数目
// 就是测试每一个存储字段结构区域的第一个字节的值,如果不为0x0D,表示存在一个字段
// 否则从此处开始不再存在字段信息 int fCount = (this._dbfHeader.HeaderLength - TDbfHeader.HeaderSize - 1) / TDbfField.FieldSize; for (int k = 0; k < fCount; k++)
{
_fileStream.Seek(TDbfHeader.HeaderSize + k * TDbfField.FieldSize, SeekOrigin.Begin); // 定位到每个字段结构区,获取第一个字节的值
byte flag = this._binaryReader.ReadByte(); if (flag == 0x0D) // 如果获取到的标志不为0x0D,则表示该字段存在;否则从此处开始后面再没有字段信息
{
return k;
}
} return fCount;
} private void ReadFields()
{
_dbfFields = new TDbfField[_fieldCount]; try
{
_fileStream.Seek(TDbfHeader.HeaderSize, SeekOrigin.Begin);
for (int k = 0; k < _fieldCount; k++)
{
this._dbfFields[k] = new TDbfField();
this._dbfFields[k].NameBytes = this._binaryReader.ReadBytes(11);
this._dbfFields[k].TypeChar = this._binaryReader.ReadByte(); this._binaryReader.ReadBytes(4); // 保留, 源代码是读 UInt32()给 Offset this._dbfFields[k].Length = this._binaryReader.ReadByte();
this._dbfFields[k].Precision = this._binaryReader.ReadByte();
this._dbfFields[k].Reserved = this._binaryReader.ReadBytes(2);
this._dbfFields[k].DbaseivID = this._binaryReader.ReadSByte();
this._dbfFields[k].Reserved2 = this._binaryReader.ReadBytes(10);
this._dbfFields[k].ProductionIndex = this._binaryReader.ReadSByte();
}
}
catch
{
throw new Exception("fail to read field information.");
}
} private void GetRecordBufferBytes()
{
this._recordBuffer = new byte[this._dbfHeader.RecordLength]; if (this._recordBuffer == null)
{
throw new Exception("fail to allocate memory .");
}
} private void CreateDbfTable()
{
if (_dbfTable != null)
{
_dbfTable.Clear();
_dbfTable = null;
} _dbfTable = new System.Data.DataTable();
_dbfTable.TableName = this.TableName; for (int k = 0; k < this._fieldCount; k++)
{
System.Data.DataColumn col = new System.Data.DataColumn();
string colText = this._dbfFields[k].GetFieldName(_encoding); if (string.IsNullOrEmpty(colText) == true)
{
throw new Exception("the " + (k + 1) + "th column name is null.");
} col.ColumnName = colText;
col.Caption = colText;
col.DataType = this._dbfFields[k].FieldType;
_dbfTable.Columns.Add(col);
}
} public void GetDbfRecords()
{
try
{
this._fileStream.Seek(this._dbfHeader.HeaderLength, SeekOrigin.Begin); for (int k = 0; k < this.RecordCount; k++)
{
if (ReadRecordBuffer(k) != DeletedFlag)
{
System.Data.DataRow row = _dbfTable.NewRow();
for (int i = 0; i < this._fieldCount; i++)
{
row[i] = this.GetFieldValue(i);
}
_dbfTable.Rows.Add(row);
}
}
}
catch (ArgumentOutOfRangeException e)
{
throw e;
}
catch
{
throw new Exception("fail to get dbf table.");
}
} private byte ReadRecordBuffer(int recordIndex)
{
byte deleteFlag = this._binaryReader.ReadByte(); // 删除标志
this._recordBuffer = this._binaryReader.ReadBytes(this._dbfHeader.RecordLength - 1); // 标志位已经读取
return deleteFlag;
} private string GetFieldValue(int fieldIndex)
{
string fieldValue = null; int offset = 0;
for (int i = 0; i < fieldIndex; i++)
{
offset += _dbfFields[i].Length;
} byte[] tmp = CopySubBytes(this._recordBuffer, offset, this._dbfFields[fieldIndex].Length); if (this._dbfFields[fieldIndex].IsInt == true)
{
int val = System.BitConverter.ToInt32(tmp, 0);
fieldValue = val.ToString();
}
else if (this._dbfFields[fieldIndex].IsDouble == true)
{
double val = System.BitConverter.ToDouble(tmp, 0);
fieldValue = val.ToString();
}
else if (this._dbfFields[fieldIndex].IsMoney == true)
{
long val = System.BitConverter.ToInt64(tmp, 0); // 将字段值放大10000倍,变成long型存储,然后缩小10000倍。
fieldValue = ((decimal)val / 10000).ToString();
}
else if (this._dbfFields[fieldIndex].IsDate == true)
{
DateTime date = ToDate(tmp);
fieldValue = date.ToString(); }
else if (this._dbfFields[fieldIndex].IsTime == true)
{
DateTime time = ToTime(tmp);
fieldValue = time.ToString(); }
else
{
fieldValue = this._encoding.GetString(tmp);
} fieldValue = fieldValue.Trim(); // 如果本子段类型是数值相关型,进一步处理字段值
if (this._dbfFields[fieldIndex].IsNumber == true || this._dbfFields[fieldIndex].IsFloat == true) // N - 数值型, F - 浮点型
{
if (fieldValue.Length == 0)
{
fieldValue = "0";
}
else if (fieldValue == ".")
{
fieldValue = "0";
}
else
{
decimal val = 0; if (decimal.TryParse(fieldValue, out val) == false) // 将字段值先转化为Decimal类型然后再转化为字符串型,消除类似“.000”的内容, 如果不能转化则为0
{
val = 0;
} fieldValue = val.ToString();
}
}
else if (this._dbfFields[fieldIndex].IsLogic == true) // L - 逻辑型
{
if (fieldValue != "T" && fieldValue != "Y")
{
fieldValue = "false";
}
else
{
fieldValue = "true";
}
}
else if (this._dbfFields[fieldIndex].IsDate == true || this._dbfFields[fieldIndex].IsTime == true) // D - 日期型 T - 日期时间型
{
// 暂时不做任何处理
} return fieldValue;
} private static byte[] CopySubBytes(byte[] buf, int startIndex, long length)
{
if (startIndex >= buf.Length)
{
throw new ArgumentOutOfRangeException("startIndex");
} if (length == 0)
{
throw new ArgumentOutOfRangeException("length", "length must be great than 0.");
} if (length > buf.Length - startIndex)
{
length = buf.Length - startIndex; // 子数组的长度超过从startIndex起到buf末尾的长度时,修正为剩余长度
} byte[] target = new byte[length];
Array.Copy(buf, startIndex, target, 0, length);
return target;
} private DateTime ToDate(byte[] buf)
{
if (buf.Length != 8)
{
throw new ArgumentException("date array length must be 8.", "buf");
} string dateStr = System.Text.Encoding.ASCII.GetString(buf).Trim();
if (dateStr.Length < 8)
{
return NullDateTime;
} int year = int.Parse(dateStr.Substring(0, 4));
int month = int.Parse(dateStr.Substring(4, 2));
int day = int.Parse(dateStr.Substring(6, 2)); return new DateTime(year, month, day);
} private DateTime ToTime(byte[] buf)
{
if (buf.Length != 8)
{
throw new ArgumentException("time array length must be 8.", "buf");
} try
{
byte[] tmp = CopySubBytes(buf, 0, 4);
tmp.Initialize();
int days = System.BitConverter.ToInt32(tmp, 0); // ( ToInt32(tmp); // 获取天数 tmp = CopySubBytes(buf, 4, 4); // 获取毫秒数
int milliSeconds = System.BitConverter.ToInt32(tmp, 0); // ToInt32(tmp); if (days == 0 && milliSeconds == 0)
{
return NullDateTime;
} int seconds = milliSeconds / 1000;
int milli = milliSeconds % 1000; // vfp实际上没有毫秒级, 是秒转换来的, 测试时发现2秒钟转换为1999毫秒的情况
if (milli > 0)
{
seconds += 1;
} DateTime date = DateTime.MinValue; // 在最小日期时间的基础上添加刚获取的天数和秒数,得到日期字段数值
date = date.AddDays(days - 1721426);
date = date.AddSeconds(seconds); return date;
}
catch
{
return new DateTime();
}
} public string TableName {
get { return System.IO.Path.GetFileNameWithoutExtension(this._dbfFileName); }
} public System.Text.Encoding Encoding {
get { return this._encoding; }
} public int RecordLength {
get {
if (this.IsFileOpened == false)
{
return 0;
} return this._dbfHeader.RecordLength;
}
} public int FieldCount {
get {
if (this.IsFileOpened == false)
{
return 0;
} return this._dbfFields.Length;
}
} public int RecordCount {
get {
if (this.IsFileOpened == false || this._dbfHeader == null)
{
return 0;
} return this._dbfHeader.RecordCount;
}
} public bool IsFileOpened {
get {
return this._isFileOpened;
}
} public System.Data.DataTable Table {
get {
if (_isFileOpened == false)
{
return null;
}
return _dbfTable;
}
} public TDbfField[] DbfFields {
get {
if (_isFileOpened == false)
{
return null;
} return _dbfFields;
}
} public static implicit operator DataTable(TDbfTable v)
{
throw new NotImplementedException();
}
}
}
使用说明:
- TestSCClearCard.TDbfTable dbf = new TestSCClearCard.TDbfTable(dbf文件名),其中dbf文件是含路径的全文件名
- dbf.Table即是获取的DataTable对象;
- dbf.DbfFields为DBF字段数组。
调用:
string dbfPath = System.Windows.Forms.Application.StartupPath + @"\cbk.dbf";
TestSCClearCard.TDbfTable dbf = new TestSCClearCard.TDbfTable(dbfPath);
DataTable dt = dbf.Table;
结果:
原文资料出自:一个C#读取DBF文件的类TDbfTable
C# 读取DBF文件到Datatable的更多相关文章
- 读取DBF文件的部分代码
private void BtnOpenInitial_Click(object sender, EventArgs e) { OpenFileDialog file = new OpenFileDi ...
- C# 解决读取dbf文件,提示Microsoft Jet 数据库引擎找不到对象的问题
前言 最新项目需要经常和dbf文件打交道,在实际场景中很多软件需要和一些老的系统进行数据交互,而这些系统都在使用foxpro数据库,读取dbf文件一般都是分为两种情况:第一:安装foxpro的驱动进行 ...
- python3 读取dbf文件报错 UnicodeDecodeError: 'gbk' codec can't decode
在读取dbf文件时由于编码问题报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xb5 in position 49: incomplete ...
- C#读取txt文件返回DATATABLE
//1.打开资源管理器 OpenFileDialog open = new OpenFileDialog(); if (open.ShowDialog() == DialogResult.OK) { ...
- 读取excel 文件到datatable
上一篇文章介绍了将datatable 内容导出到excel 文件,这里介绍如何将一个excel 文件读取出来,并保持到datatable 中,实际这样的应用场景也是经常遇到的. 这里继续使用了Micr ...
- 读取DBF文件数据
#region 返回DBF表 public static System.Data.DataTable getDTFromDBF(string fullPath) { string pDir = Sys ...
- 【C#】采用OleDB读取Excel文件转DataTable
using System; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using ...
- 使用Python读取Dbf文件
DBF:一种特殊的文件格式!表示数据库文件,Foxbase,Dbase,Visual FoxPro等数据库处理系统所产生的数据库文件! DBF 数据库是常用的桌面型数据库,它曾经被各企业.事业单位广泛 ...
- 读取Excel文件到DataTable中
private static string[] GetExcelSheetNames(OleDbConnection conn) { DataTable dtbSh ...
- shp系列(六)——利用C++进行Dbf文件的写(创建)
上一篇介绍了shp文件的创建,接下来介绍dbf的创建. 推荐结合读取dbf的博客一起看! 推荐结合读取dbf的博客一起看! 推荐结合读取dbf的博客一起看! 1.Dbf头文件的创建 Dbf头文件的结构 ...
随机推荐
- Freertos学习:00-介绍
--- title: rtos-freertos-000-介绍 EntryName: rtos-freertos-00-about date: 2020-06-09 23:21:44 categori ...
- 手把手带你使用JWT实现单点登录
JWT(英文全名:JSON Web Token)是目前最流行的跨域身份验证解决方案之一,今天我们一起来揭开它神秘的面纱! 一.故事起源 说起 JWT,我们先来谈一谈基于传统session认证的方案以及 ...
- Redis缓存满了,如何存放数据?缓存淘汰策略
我们的redis使用的是内存空间来存储数据的,但是内存空间毕竟有限,随着我们存储数据的不断增长,当超过了我们的内存大小时,即在redis中设置的缓存大小(maxmeory 4GB),redis会怎么处 ...
- 构筑开放式大数据架构,Apache Kyuubi和NDH荣登开源OSCAR
[点击了解更多网易大数据技术] 在9月16日召开的"2022 OSCAR开源产业大会"上,中国信息通信研究院发布了一系列开源研究成果和开源表彰,网易数帆发起的开源项目Apache ...
- 服务之间的调用之RPC深入理解
一:RPC RPC 即远程过程调用(Remote Procedure Call Protocol,简称RPC),像调用本地服务(方法)一样调用服务器的服务(方法).通常的实现有 XML-RPC , J ...
- Elasticjob执行job幂等
ElasticJob的幂等机制,是指作业分片执行的幂等,他需要做到以下两点: 同一个分片在当前作业实例上不会被重复执行 一个作业分片不能同时在多个作业实例上执行 如何实现幂等 场景模拟:存在任务A执行 ...
- python raise异常处理
python raise异常处理 一般最简单的异常处理是try except: try: f = open('test.txt') except Exception as e: print(e) f ...
- 对比python学julia(第二章)--(第二节)勾股树—分形之美
2.1.问题描述 二话不说,先上图: 图一.勾股定理图形 图二.勾股树 ...
- stable diffusion 实践与测试
stable diffusion 实践与测试 放大 原图高清放大 原始图片 当不满意图片质量的时候 使用stable diffusion进行二次处理 选择适合图片风格的模型,再次根据图片写出提示词 输 ...
- 【Windows】固定Win系统的IP地址
是我迟钝了,突然想到这个事情就记一下 先开终端查看IP信息 : IPCONFIG 找到当前连接: IPv4协议设置: 家庭网络设置就这样,公司内网有自己的一个DNS服务地址,这个网管知道 在Win11 ...