1. 程式人生 > >shp系列(六)——利用C++進行Dbf檔案的寫(建立)

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的建立。