zoukankan      html  css  js  c++  java
  • 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, '', 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, '', 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, '', 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, '', 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, '', 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 ) = '';
    		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, '', 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的创建。

  • 相关阅读:
    跳台阶问题
    最大连续子数组和
    寻找和为定值的若干个数
    MySQL- 用Navicat通过隧道连接到远程数据库
    CDH- 测试mr
    Sqoop- sqoop将mysql数据表导入到hive报错
    CDH- CDH大数据集群运维
    Spring- 异常org.xml.sax.SAXParseException; systemId: http://www.springframework.org/schema/context/; lineNumber: 1; columnNumber: 55; 在 publicId 和 systemId 之间需要有空格。
    Spring- 通过Xml的方式完成Bean的实例化
    Spring- Bean的命名
  • 原文地址:https://www.cnblogs.com/fan-0802-WHU/p/10159097.html
Copyright © 2011-2022 走看看