shp系列(六)——利用C++进行Dbf文件的写(创建)

上一篇介绍了shp文件的创建,接下来介绍dbf的创建。

推荐结合读取dbf的博客一起看!

推荐结合读取dbf的博客一起看!

推荐结合读取dbf的博客一起看!

1.Dbf头文件的创建

Dbf头文件的结构如下:

记录项数组说明:

字段类型说明:

关于每项的具体含义参照读取dbf文件的解释,这里重点解释几项:

  • HeaderByteNum指dbf头文件的字节数,数值不用除于2,具体为:从version到Reserved2(共32) + n个字段 * 每一个字段长度 32 + terminator。
  • RecordByteNum指每条记录的字节数,数值不用除于2,RecordByteNum根据记录的实际长度来写,具体为:∑每个字段的字节数(字段数量根据读取打开shp的字段数决定)。例如我的例子中写了八个字段,则一条记录的实际长度为:1(deleteFlag) + 10 + 32 + 16 + 10 + 10 + 8 + 19 + 19 = 1 + 124 =125。

2.Dbf记录实体的创建

记录实体就是每条记录,一个记录有多个字段,部分字段上存储必要的信息。由于实际上每个shp文件的表的字段数可能不一样,并且每个字段的类型不固定,需要每次判定字段类型,然后根据不同类型设置来输出信息。

但是这费时费力,根据实际情况,简化一下,读取已知字段数和字段类型的DBF的信息,或者说,根据实际需要的字段数和字段类型来输出,牺牲普遍性来获取快速结果,以后修改也不困难。

3.读取Dbf的代码

void WriteDbf(CString filename)
{
	//创建与Shp文件同名的指针
	int n = filename.ReverseFind(‘.‘);
	filename = filename.Left(n);
	filename = filename + ".dbf";
	FILE* m_DbfFile_fp;
	if ((m_DbfFile_fp = fopen(filename, "wb")) == NULL)
		return;

	//****创建dbf文件的文件头
	int i, j;
	BYTE version = 4;
	fwrite(&version, 1, 1, m_DbfFile_fp);
	CTime t = CTime::GetCurrentTime();
	int d = t.GetDay();
	int y = t.GetYear() % 2000;
	int m = t.GetMonth();
	BYTE date[3];
	date[0] = y;
	date[1] = m;
	date[2] = d;
	for (i = 0; i<3; i++)                           //记录时间
		fwrite(date + i, 1, 1, m_DbfFile_fp);

	int RecordNum = map->layer->objects.size();     //文件中的记录条数
	fwrite(&RecordNum, sizeof(int), 1, m_DbfFile_fp);
	short HeaderByteNum = 0;                        //文件头中的字节数,暂时写0,后面要返回来修改
	fwrite(&HeaderByteNum, sizeof(short), 1, m_DbfFile_fp);
	short RecordByteNum = 0;                        //一条记录中的字节长度,暂时写0,后面要返回来修改
	fwrite(&RecordByteNum, sizeof(short), 1, m_DbfFile_fp);
	short Reserved1 = 0;
	fwrite(&Reserved1, sizeof(short), 1, m_DbfFile_fp);
	BYTE Flag4s = 0;
	fwrite(&Flag4s, sizeof(BYTE), 1, m_DbfFile_fp);
	BYTE EncrypteFlag = 0;
	fwrite(&EncrypteFlag, sizeof(BYTE), 1, m_DbfFile_fp);
	int Unused[3] = { 0,0,0 };
	for (i = 0; i<3; i++)
		fwrite(Unused + i, sizeof(int), 1, m_DbfFile_fp);
	BYTE MDXFlag = 0;
	fwrite(&MDXFlag, sizeof(BYTE), 1, m_DbfFile_fp);
	BYTE LDriID = 0;
	fwrite(&LDriID, sizeof(BYTE), 1, m_DbfFile_fp);
	short Reserved2 = 0;
	fwrite(&Reserved2, sizeof(short), 1, m_DbfFile_fp);

	//****写记录项数组
	int fieldscount = fieldscount_final;          //字段数量可以根据读取的shp文件确定
	for (i = 0; i< fieldscount; i++)
	{
		RecordItem recordItem = recordItems[i];   //recordItems是自己设置的记录项数组(字段)的数组,
												  //根据需求设定每个记录项数组(字段)的参数,以供调用
		//****name--------11     bytes
		fwrite(recordItem.name, 11, 1, m_DbfFile_fp);

		//****FieldType----1     bytes
		fwrite(&(recordItem.fieldType), sizeof(BYTE), 1, m_DbfFile_fp);

		//****Reserved3----4     bytes
		fwrite(&(recordItem.Reserved3), sizeof(int), 1, m_DbfFile_fp);

		//****FieldLength--1     bytes
		fwrite(&(recordItem.fieldLength), sizeof(BYTE), 1, m_DbfFile_fp);

		//****DecimalCount-1   bytes
		fwrite(&(recordItem.decimalCount), sizeof(BYTE), 1, m_DbfFile_fp);

		//****Reserved4----2     bytes
		fwrite(&(recordItem.Reserved4), sizeof(short), 1, m_DbfFile_fp);

		//****WorkID-------1    bytes
		fwrite(&(recordItem.workID), sizeof(BYTE), 1, m_DbfFile_fp);

		//****Reserved5----10   bytes
		for (j = 0; j<5; j++)
			fwrite(recordItem.Reserved5 + j, sizeof(short), 1, m_DbfFile_fp);

		//****MDXFlag1-----1  bytes
		fwrite(&(recordItem.mDXFlag1), sizeof(BYTE), 1, m_DbfFile_fp);
	}
	BYTE terminator = 13;                       //头文件终止标识符
	fwrite(&terminator, sizeof(BYTE), 1, m_DbfFile_fp);

	fseek(m_DbfFile_fp, 8, SEEK_SET);           //转到头文件字节数RecordByteNum,开始重写
	HeaderByteNum = 32 + 32 * fieldscount + 1;  //从version到Reserved2(共32) + n个字段 * 每一个字段长度 32 + terminator
	fwrite(&HeaderByteNum, sizeof(short), 1, m_DbfFile_fp);

	RecordByteNum = 1 + 124;                    //RecordByteNum根据记录的实际长度来写,∑每个字段的长度
												// 1 + 10 + 32 + 16 + 10 + 10 + 8 + 19 + 19 = 1 + 124 =125
	fseek(m_DbfFile_fp, 10, SEEK_SET);          //转移每条记录长度RecordByteNum
	fwrite(&RecordByteNum, sizeof(short), 1, m_DbfFile_fp);
	fseek(m_DbfFile_fp, 0, SEEK_END);
	//****写dbf文件头结束

	//****写每条记录
	BYTE deleteFlag;
	char media[40];
	for (i = 1; i <= RecordNum; i++){
		CGeoPolygon* polygon = (CGeoPolygon*)map->layer->objects[i - 1];
		deleteFlag = 32;                                    //默认写32
		fwrite(&deleteFlag, sizeof(BYTE), 1, m_DbfFile_fp); //读取删除标记  1字节

		//****写 ObjectID int
		stringstream ss;
		ss << (i - 1);
		string str = ss.str();
		int length = str.length();
		memset(media, ‘\0‘, 40);
		for (int m = 0; m < 10 - length; m++)
			media[m] = ‘ ‘;

		for (int c = 10 - length; c < 10; c++)
			media[c] = str[c - 10 + length];

		for (j = 0; j<10; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--10					

		//****写Dest string
		memset(media, ‘\0‘, 40);
		media[0] = ‘/‘;
		for (int c = 1; c <32; c++)
			media[c] = ‘ ‘;

		for (j = 0; j<32; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--32

		//****写Ec string
		for (j = 0; j<16; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--16

		//****写EcRm int
		ss << -8888;
		str = ss.str();
		length = str.length();
		memset(media, ‘\0‘, 40);
		for (int m = 0; m < 10 - length; m++)
			media[m] = ‘ ‘;

		for (int c = 10 - length; c < 10; c++)
			media[c] = str[c - 10 + length];

		for (j = 0; j<10; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--10

		//****写Elevt int
		for (j = 0; j<10; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--10

		//****写Cc int
		str = polygon->objectAttribute;
		memset(media, ‘\0‘, 40);
		length = str.length();
		for (int c = 0; c < length; c++)
			media[c] = str[c];

		for (int c = length; c < 8; c++)
			media[c] = ‘ ‘;

		for (j = 0; j<8; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--8

		//****写shape_length double
		CString str1;
		double shape_length = polygon->getAllLength();
		str1.Format(_T("%.11e"), shape_length);
		memset(media, ‘\0‘, 40);
		media[0] = ‘ ‘;
		for (int c = 1; c < 16; c++)
			media[c] = str1[c - 1];

		if (str1.GetLength() == 18)
			for (int c = 16; c < 19; c++)
				media[c] = str1[c - 1];
		else {
			media[16] = ‘0‘;
			media[17] = str1[15];
			media[18] = str1[16];
		}
		//*(media + length ) = ‘\0‘;
		for (j = 0; j<19; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--19

		//****写shape_Area double
		double shape_area = polygon->shapeArea;
		str1.Format(_T("%.11e"), shape_area);
		memset(media, ‘\0‘, 40);
		media[0] = ‘ ‘;
		for (int c = 1; c < 16; c++)
			media[c] = str1[c - 1];

		if (str1.GetLength() == 18)
			for (int c = 16; c < 19; c++)
				media[c] = str1[c - 1];
		else {
			media[16] = ‘0‘;
			media[17] = str1[15];
			media[18] = str1[16];
		}
		for (j = 0; j<19; j++)
			fwrite(media + j, sizeof(char), 1, m_DbfFile_fp);   //--19
	}
	//****写dbf文件记录结束

	fclose(m_DbfFile_fp);
}

  

下一篇将介绍Shx的创建。

原文地址:https://www.cnblogs.com/fan-0802-WHU/p/10159097.html

时间: 2024-08-30 07:05:45

shp系列(六)——利用C++进行Dbf文件的写(创建)的相关文章

shp系列(七)——利用C++进行Shx文件的写(创建)

之前介绍了Shp文件和Dbf的写(创建),最后来介绍一下Shx文件的写(创建).Shx文件是三者之中最简单的一个,原因有两个:第一是Shx文件的头文件与Shp文件的头文件几乎一样(除了FileLength):第二是Shx文件的主体只有两个记录项,分别是Offset和ContentLength. 推荐结合读取shx的博客一起看! 推荐结合读取shx的博客一起看! 推荐结合读取shx的博客一起看! 1.Shx头文件 Shx头文件的各项和Shp文件一样,字节数为100.FileLength代表本Shx

python常识系列07--&gt;python利用xlwt写入excel文件

前言 读书之法,在循序而渐进,熟读而精思.--朱熹 抽空又来写一篇,毕竟知识在于分享! 一.xlwt模块是什么 python第三方工具包,用于往excel中写入数据:(ps:只能创建新表格,不能修改表格内容!!) 它支持 xlsx 和 xls 格式的excel表格: 与之对应的还有一个xlrd包,用于读取excel中的数据. 二.安装xlwt模块 命令行中输入:pip install xlwt 下载安装包进行离线安装 三.xlwt应用举例 3.1 xlwt基本应用实例 import xlwt #

linux下C++开发系列(六)——文件IO相关的系统调用

linux操作系统中,文件是最基本和最重要的抽象,linux遵循一切皆文件的理念.按照不同的属性,文件可以分为普通文件和特殊文件.特殊文件是以文件方式表示的内核对象,linux支持四种类型的特殊文件: 1.块设备文件 (例如硬盘设备) 2.字符设备文件(例如键盘设备) 3.命名管道 (主要是进程间通信使用) 4.Unix域套接字(主要是网络通信使用) linux系统对于文件的操作,提供了一系列的系统调用个,主要分为以下几类: 1.创建文件(creat) 2.打开文件(open) 3.读文件(re

【C++自我精讲】基础系列六 PIMPL模式

0 前言 很实用的一种基础模式. 1 PIMPL解释 PIMPL(Private Implementation 或 Pointer to Implementation)是通过一个私有的成员指针,将指针所指向的类的内部实现数据进行隐藏. 2 PIMPL优点 举例: //x.h class X { public: void Fun(); private: int i; //add int i; }; //c.h #include <x.h> class C { public: void Fun()

利用TinyXML解析XML文件

下载地址:TinyXML 解压缩TinyXML后,找到六个文件: tinystr.h.tinystr.cpp.tinyxml.h.tinyxml.cpp.tinyxmlerror.cpp.tinyxmlparser.cpp 将这六个文件放在你的C++工程中,跟你的源文件在同一目录下. 新建一个XML文件,命名为Students.xml : <Class name="计算机软件班"> <Students> <student name="张三&quo

Java读取Level-1行情dbf文件极致优化(3)

最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1行情没有Level-2快,但是作为系统支持的行情源,我们还是需要优化它,使得从文件读取,到用户通过socket收到行情,端到端的时延尽可能的低.本文主要介绍对level-1行情dbf文件读取的极致优化方案.相信对其他的dbf文件读取应该也有借鉴意义. Level-1行情是由行情小站,定时每隔几秒把d

java把dbf文件写入远程2003服务器

重要的事情说三遍,有木有,java把dbf文件写入远程2003服务器,第一遍,第二遍,第三遍-够了,王二,还有完没有,赶紧点 需求 今天早晨,王二(也就是我)接到一个需求: 把行情的dbf库写入到远程windows server2003上! 分析 之前,我就写过一篇Java操作DBF文件数据库,但怎么把dbf写入到远程服务器上,这好像需要点什么. 于是我就去问度娘啊,看看有没有什么封装好的jar包之类的,好拿来用用. 折腾了一会关键字,终于找到了一篇Java读写Windows共享文件夹,感谢博主

iOS流布局UICollectionView系列六——将布局从平面应用到空间

iOS流布局UICollectionView系列六--将布局从平面应用到空间 一.引言 前面,我们将布局由线性的瀑布流布局扩展到了圆环布局,这使我们使用UICollectionView的布局思路大大迈进了一步,这次,我们玩的更加炫一些,想办法将布局应用的空间,你是否还记得,在管理布局的item的具体属性的类UICollectionViewLayoutAttributrs类中,有transform3D这个属性,通过这个属性的设置,我们真的可以在空间的坐标系中进行布局设计.iOS系统的控件中,也并非

Cocos2d-x 系列六之数据操作

一.定时器  在cocos2d-x中, 类似定时器的操作,不需要额外的写Timer,实际上,在Node元素中,已经添加了定时执行的功能: 先来看看在Node中的定义 // ... bool Node::isScheduled(SEL_SCHEDULE selector) { return _scheduler->isScheduled(selector, this); } void Node::scheduleUpdate() { scheduleUpdateWithPriority(0); }