1.基于C#的Dbf读写(文件结构概述)

愿你出走半生,归来仍是少年! 

环境:.NET FrameWork4.5、.Net 6

1.简述

        在地理信息系统中,有很多的常用数据格式,类似Shapefile、Dxf等等,在不同的商业或开源平台中都有对其可靠的支持。DBF数据文件作为Shapefile文件的属性存储文件,出现的情况特别多;除此之外,现如今特别多的测绘公司对于数据的内业处理也还是保存在DBF中通过VFP进行处理。

        虽然都是DBF文件,但是其内部存在不同的文件类型,这个会导致现如今在Git上找到的开源库有时候会出现有些dbf在打开时出现错误的情况。为了能够方便、快捷的读写DBF数据,不少开发者需要安装驱动,通过OLE DB的方式连接操作。

        本文通过二进制流的方式进行DBF文件的解析、读取、写入,同时说明DBF文件的构成。

1.1.C#依赖知识

C#数据类型字节数
数据类型所占字节数
Byte1
Short2
Int4
Char1

        后续的文件读写操作都是基于C#中的BinaryReader进行。

        

2.DBF构成

        每个DBF文件依次存在以下几个部分:头文件区域字段描述区域后链信息(VFP存在,其它版本没发现)数据内容区域

        通过一下代码创建面向指定DBF文件的流读取器:

new BinaryReader(new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read, 100000));

2.1.头文件区域

        头文件区域共计占32字节,具体分布如下。

文件头结构
字节范围字节数读取类型说明
01Byte文件类型
11Byte文件最后修改日期,年 YY
21Byte文件最后修改日期,月 MM
31Byte文件最后修改日期,日 DD
4-74Int数据记录数量,总行数
8-92Short文件头的字节长度(头文件区域字段描述区域、结束符(0x0D后链信息(VFP存在,其它版本没发现)
10-112short每一行数据记录的字节长度
12-2716未使用保留区域
281Byte表的标记                
291Byte Language Driver ID (LDID),文件编码代码页标记
30-312未使用保留区域

2.1.1.文件类型读取

 // 获取Dbf的第一个字节,代表dbf文件类型,参照 DbfFileType 0FileType = reader.ReadByte();

        创建BinaryReader后,通过 ReadByte()方法读取文件第一个字节,获取到Dbf的文件类型,具体类型清单如下,通过对比可得知当前的DBF类型。

DBF文件类型
编码说明
0x02 FoxBASE
0x03FoxBASE+/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

     2.1.2.最后修改日期读取

 // 获取更新日期:年 1int year = reader.ReadByte();// 获取更新日期:月 2int month = reader.ReadByte();// 获取更新日期:日 3int day = reader.ReadByte();try{//转换为日期UpdateDate = new DateTime(year + 1900, month, day);}catch{//获取文件的最后一次编辑时间UpdateDate = new FileInfo(Filename).LastWriteTime;}

        通过三次的ReadByte()方法依次读取出年月日,并转换为对应的日期。当出错时就以文件的最后编辑时间作为参照。

2.1.3.数据记录数量/总行数

  // 读取数据总数,int 4字节长度  4-7NumRecords = reader.ReadInt32();

        通过ReadInt32()方法一次性读取4个字节,获得该DBF文件中现有的数据记录总数。 

2.1.4.文件头总字节长度

  //  读取文件的头文件长度 short 2字节长度 8-9HeaderLength = reader.ReadInt16();

        通过ReadInt16()方法一次性读取2个字节,获得该DBF文件的头文件总字节长度。 

2.1.5.每行数据的字节长度

 // 读取每行记录的长度 short 2字节长度 10-11RecordLength = reader.ReadInt16();

         通过ReadInt16()方法一次性读取2个字节,获得该DBF文件中每一行数据记录的长度。 

2.1.6.保留区、标记

 // 跳过系统保留区域 12-27  ;表的标记 28reader.ReadBytes(17);

2.1.7.代码页标记

 // 读取 Language Driver ID (LDID)  byte 1字节长度 29LanguageDriverId = reader.ReadByte();

         通过ReadByte()方法读取代码页标记,用于设置编码。 

2.1.8.保留区

//  跳过系统保留区 30-31 
reader.ReadBytes(2);

2.2.字段描述区域

        字段描述区域包含了该DBF中的所有字段信息。每个字段的信息占用共计32字节长度,然后以0x0d结束。若该DBF包含后链信息,则后续是后链信息;若不包含后链信息,则后续是数据内容区域

        每个字段的信息32字节长度分布结构如下:

2.2.1.字段名称读取

// 读取字段名称 :字段名,10字节,0-9;保留区,默认为0,1字节,10
string name = Encoding.GetString(reader.ReadBytes(11));//获取保留区序号
int nullPoint = name.IndexOf((char)0);//裁剪
if (nullPoint != -1)
{name = name.Substring(0, nullPoint);
}

        通过读取前面11个字节,然后获取第一个0的位置进行裁剪获得名称。

2.2.2.字段类型读取

  // 字段类型,1字节,11char code = (char)reader.ReadByte();

        获取字段类型后可得知其对应的数据类型,具体类型如下:

2.2.3.字段偏移量读取

// 字段偏移量,int 4字节,12-15 
int dataAddress = reader.ReadInt32();

 2.2.4.字段长度读取

// 字段长度,byte 1字节 16
byte tempLength = reader.ReadByte();

 2.2.5.字段小数位数读取

// 小数位数,byte 1字节 17
byte decimalcount = reader.ReadByte();

  2.2.6.标记及保留区读取

  //  字段标记及保留区 ,字段标记 byte 1字节 18,;保留区  19-31reader.ReadBytes(14);

   2.2.7.字段描述区整体读取

 Fields = new List<DbfField>();bool readFieldFinish = false;while (!readFieldFinish){// 读取字段名称 :字段名,10字节,0-9;保留区,默认为0,1字节,10string name = Encoding.GetString(reader.ReadBytes(11));//获取保留区序号int nullPoint = name.IndexOf((char)0);//裁剪if (nullPoint != -1){name = name.Substring(0, nullPoint);}// 字段类型,1字节,11char code = (char)reader.ReadByte();// 字段偏移量,int 4字节,12-15 int dataAddress = reader.ReadInt32();// 字段长度,byte 1字节 16byte tempLength = reader.ReadByte();// 小数位数,byte 1字节 17byte decimalcount = reader.ReadByte();//  字段标记及保留区 ,字段标记 byte 1字节 18,;保留区  19-31reader.ReadBytes(14);DbfField myField = new DbfField(name, code, tempLength, decimalcount){DataAddress = dataAddress};Fields.Add(myField);dt.Columns.Add(myField);long pst = reader.BaseStream.Position;//_numFields = (HeaderLength - FileDescriptorSize - 1) / FileDescriptorSize;//  字段描述区的结束符  0x0d,有些版本后面有263个字节包含后链信息(相关数据库 (.dbc) 的相对路径)。// 计算字段数量:【头长度-文件描述长度(32)-结束符长度(1)】/单字段描述区长度(32)进行计算会忽略263字符的情况//  如果第一个字节为 0x00,则该文件不与数据库关联。因此数据库文件本身总是包含 0x00。byte last = reader.ReadByte();if (last == 0x0d){readFieldFinish = true;}else{reader.BaseStream.Position = pst;}}

        整体读取时需要注意的是每次读取完成后需要进行下一个字节的判断,当这个字节是0x0d时就代表字段描述区域已经完结了。这样的话可以避过后链信息区域的干扰,获取到正确的字段集合。

2.3.数据内容区域

        字段描述区域包含了该DBF中的所有数据记录,每条记录的字节长度固定为2.1.5中获取到的每行数据的字节长度,每个字段的长度为2.2.4.中获取到的字段长度。通过字节长度读取每个字段对应的数据内容,并根据在2.2.2.中获取的字段类型进行转换,便可以获取到对应的数据。

        每条记录的第一个字节都是该记录的删除标记,当内容为空格 (0x20)时,表示该记录未标记删除,当内容为星号 (0x2A)时,表示该记录已标记为删除。

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646013.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt/QML编程之路:ListView实现横排图片列表的示例(40)

ListView列表,在QML中使用非常多,排列一个行,一个列或者一个表格,都会用到ListView。 ListView显示从内置QML类型(如ListModel和XmlListModel)创建的模型中的数据,或在C++中定义的从QAbstractItemModel或QAbstract ListModel继承的自定义模型类中的数据。 ListView有一…

未来零售策略解密:品牌全球化与新兴零售模式的交汇

随着全球数字化浪潮的不断推进&#xff0c;品牌出海已经成为零售业的重要发展方向。在这个多元化、全球化的市场中&#xff0c;线上线下融合和智能零售等新兴模式正迅速崛起&#xff0c;为品牌开拓更广阔的国际市场提供了丰富的可能性。本文Nox聚星将和大家探讨新兴零售模式在全…

Windows云服务器如何配置多用户登录?(Windows 2012)华为云官方文档与视频地址

Windows云服务器如何配置多用户登录&#xff1f;&#xff08;Windows 2012&#xff09;_弹性云服务器 ECS_故障排除_多用户登录_华为云 打开任务栏左下角的“服务器管理器”&#xff0c;在左侧列表中选中“本地服务器” 然后将右侧“远程桌面”功能的选项修改为“启用”&#x…

Spring Boot 使用validation校验参数

Spring Boot 使用validation校验参数 项目场景&#xff1a;引入依赖使用校验代码实体类 打完收工&#xff01; 项目场景&#xff1a; 在看公司代码的时候&#xff0c;发现是用了Spring Boot Validation去检验参数的&#xff0c;但是后面又在代码里去检验参数去了&#xff0c;而…

携程这几招,让千万用户真正实现低碳出游

近日&#xff0c;法大大与企业绿色发展研究院联合发布了《2023年签约减碳与低碳办公白皮书》&#xff08;点击阅读及下载&#xff1a;法大大推出“签约减碳”年度账单&#xff0c;引领低碳办公新风潮&#xff09;&#xff0c;该白皮书基于《低碳办公评价》标准倡导的创新减碳技…

基于微信甘肃兰州某停车场车位预约小程序系统设计与实现 研究背景和意义、国内外现状

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

【screw-core依赖】Java使用screw-core依赖库生成数据库表结构文档

这篇文章,主要介绍Java使用screw-core依赖库生成数据库表结构文档【知识星球】。 目录 一、生成数据库文档 1.1、引入依赖 1.2、基本使用

【必剪】鬼畜rap和鬼畜剧场的区别?

在【选择素材】中&#xff0c;每个素材下会有一个标签显示支持哪种的鬼畜形式&#xff0c;在点击一个两种格式的有【鬼畜剧场】和【鬼畜rap】这两中的主要区别在于 【鬼畜剧场】&#xff1a;对素材进行人工编排&#xff0c;创作自己原创的剧情作 【鬼畜rap】&#xff1a;对于素…

分析Vue3生命周期

一.什么是生命周期 在Vue中&#xff0c;生命周期是组件从创建到销毁的整个过程中的不同阶段。Vue组件的生命周期主要由一系列的钩子函数&#xff08;hook functions&#xff09;组成。 以下是Vue组件生命周期的主要阶段&#xff1a; 1. 创建阶段&#xff1a; - beforeCre…

专业140+总分420+复旦大学957信号与系统考研经验复旦电子信息与通信

今年专业957信号与系统140&#xff0c;数二140&#xff0c;总分420&#xff0c;顺利上岸复旦大学&#xff0c;回顾这一年的复习&#xff0c;有起有落&#xff0c;也有过犹豫和放弃&#xff0c;好在都坚持下来了&#xff0c;希望大家考研复习要不忘初心&#xff0c;困难肯定是很…

win10安装postgresql 12.17

一、下载地址 Community DL Page 下载的12.17版本 二、安装 直接点“下一步、下一步”就可以&#xff0c;注意几点是在其中需要配置&#xff1a; 1.安装路径 2.data目录位置&#xff08;默认是安装路径下的data文件夹&#xff09; 3.端口&#xff08;默认5432&#xff09…

多元跨界、戮力谐老!2024深圳国际户外运动展览会再创运动生活新方式

COSP Shenzhen 2024国际户外运动用品与时尚展 2024年3.14-16日 深圳会展中心(福田馆&#xff09; COSP Shanghai 2024国际户外运动用品与时尚展 2024年9.05-07日 上海世博展览馆&#xff08;浦东&#xff09; 展会概述&#xff1a; 作为国内最具影响力的户外运动展会之一…

BOM location 对象详解

location 对象 ​通过 location 对象可以以编程方式操纵浏览器的导航系统。通过设置这个对象上的属性&#xff0c;可 以改变浏览器 URL 中的某一部分或全部。 location 是最有用的 BOM 对象之一&#xff0c;提供了当前窗口中加载文档的信息&#xff0c;以及通常的导航功能。 …

bt1120和bt656时序说明

时序说明 同步码说明 数据传输时序

Linux中并发程序设计(进程的创建和回收、exec函数使用)

进程的创建和回收 进程概念 概念 程序 存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09; 静态的 进程 执行一个程序所分配的资源的总称 动态的进程和程序比较 注&#xff1a;进程是存在RAM中&#xff0c;程序是存放在ROM(flash)中的进程内容 BSS段&#xff…

2024 年入局大模型:是否为时已晚?

随着技术的不断发展&#xff0c;大模型&#xff08;例如GPT-4&#xff09;在自然语言处理等领域表现出色。然而&#xff0c;随着时间的推移&#xff0c;一些人可能会质疑在2024年入局大模型是否为时已晚。本文将探讨这个问题&#xff0c;并提供观点和观察。 2024年&#xff0c;…

【数据结构与算法】栈(Stack)之 浅谈数组和链表实现栈各自的优缺点

文章目录 1.栈介绍2. 哪种结构实现栈会更优&#xff1f;3.栈代码实现&#xff08;C语言&#xff09; 往期相关文章&#xff1a; 线性表之顺序表线性表之链表 1.栈介绍 栈是一种特殊的线性表&#xff0c;只允许在栈顶&#xff08;Top&#xff09;进行插入和删除元素操作&#…

win下安装es可视化工具——elasticsearch head(win_Elasticsearch)

一、head简介 Elasticsearch Head是集群管理、数据可视化、增删改查、查询语句可视化工具。 二、node.js的安装 ElasticSearch-head 依赖于node.js 下面先安装node.js 下面是node.js下载地址http://nodejs.cn/download/&#xff1b; 下载后&#xff0c;就是一个安装包&#xf…

session反序列化

据陈腾师傅所说&#xff1a; 1.漏洞产生原因&#xff1a;写入格式和读取格式不一样。 下面是三种常见的存储格式&#xff1a; 处理器 对应的存储格式 php键名竖线经过serialize()函数序列化处理的值php_serialize(php>5.54)经…

IDEA导出jar

1、选择导出方式 2、选择Main Class 3、构建jar