About how to use C++ to read .dbf files

.dbf file format

The description of the .dbf file format can be found in these two blogs:

  1. DBF file format
  2. shp series (three)

I will not go into details about the dbf file format, because the above two blogs have already talked very clearly. This article is mainly about how to read arbitrary .dbf files through C++.

C++ code

1.Field class

.dbf is a table file, which is stored in binary mode, and the header file is variable length.
Since it is a table file, there is a concept of ranks. The rows of the DBF table are represented as records, and the columns are represented as fields. Therefore, you can design a field class, namely Class Field.
code show as below:

/********************************************************************************
 * Description: this header file is designed for reading and saving 
 *              the field in the dBaseFile
 * 
 * Author: Mr.Zhang Wanglin(Geocat)
 * 
 * Date: 2020.06.07
********************************************************************************/

#ifndef FIELD_H
#define FIELD_H

#include <vector>
using std::vector;

class Field
{
    
    
public:
    Field();

    void storeFieldContent();

    enum _eRecordItemDataType{
    
    B,C,D,G,L,M,N};  // 记录项的数据类型

    // 属性—— 1. 文件头中字段的内容:32字节

        // 0-10字节为记录项(字段)名称
    char _cTitle[11];

        // 11字节为记录项的数据类型
    char _cDataType;

        // 16字节为记录项长度,BYTE类型,1个字节
            // 注:可以用强制类型转换将记录项长度转换成int型
    unsigned char _ucFieldLength;

        // 字段内容
    char _cFieldContent[100];

    vector<char*> _vField;  // 存储字段的内容
};

#endif // FIELD_H

2.DBaseFile class

The DBaseFIle class contains the contents of the file header and the contents of all fields.
The header file code is as follows:

/********************************************************************************
 * Description: this header file is designed for reading and saving
 *              the field in the dBaseFile
 *
 * Author: Mr.Zhang Wanglin(Geocat)
 *
 * Date: 2020.06.08
********************************************************************************/
#ifndef DBASEFILE_H
#define DBASEFILE_H

#include <string>
#include <vector>
#include <fstream>
#include "field.h"

using namespace std;

class DBaseFile
{
    
    
public:
    // 构造函数
    DBaseFile();
    DBaseFile(string sFilename);

    // 自定义函数
        // loadFile(string)函数将文件读取到内存
    void loadFile(string sFilename);
    void showData();

    // 数据表的增删改查
    void addRec(int iColum, int iLine, unsigned char* ucData);
    void deleteRec(int iColum, int iLine, unsigned char* ucData);
    void modifyRec(int iColum, int iLine, unsigned char* ucData);
    void checkRec(int iColum, int iLine, unsigned char* ucData);

    // 属性
        // 文件头中的内容
    int _iRecCount; // 记录的条数——行数
    int _iFieldCount;   // 字段数——列数
    short _BytesOfFileHead; // 文件头中的字节数
    short _BytesOfEachRecord;   // 每一条记录的字节数

        // 内存中用来存储相应数据的变量
    Field* _pField; // 用来创建某个字段
    string _sFilename;  // 用来存储文件名
//    vector<char*> _vFieldNameInFileHead;   // 文件头中的字段名
    vector<Field*> _vTable;  // 用来存储所有的字段的内容,是一个存储字段容器

protected:
    void readFileHead(ifstream& inFile);
    void readFileRecord(ifstream& inFile);
    bool isReadFileOK(string sFilename);
};

#endif // DBASEFILE_H

3. Concrete realization

field.cpp

#include "field.h"

Field::Field()
{
    
    

}

void Field:: storeFieldContent()
{
    
    
    _vField.push_back(_cFieldContent);
}

dbasefile.cpp

#include "dbasefile.h"
#include <iostream>

DBaseFile::DBaseFile()
{
    
    }

DBaseFile::DBaseFile(string sFilename)
{
    
    
    this->_sFilename=sFilename;
}

void DBaseFile:: loadFile(string sFilename)
{
    
    
    ifstream inFile(sFilename,ios::binary|ios::in);

    if(!isReadFileOK(sFilename))
        return;
    readFileHead(inFile);
    readFileRecord(inFile);
    inFile.close();
}

void DBaseFile:: showData()
{
    
    
    for(unsigned int i=0;i<_vTable.size();i++)
    {
    
    
        cout<<_vTable[i]->_cTitle<<"\t";
    }
    cout<<"\n";
    for(int i=0;i<_iRecCount;i++)
    {
    
    
        for(unsigned int j=0;j<_vTable.size();j++)
            cout<<_vTable[j]->_vField[i]<<"\t";
        cout<<endl;
    }
}

bool DBaseFile::isReadFileOK(string sFilename)
{
    
    
    ifstream inFile(sFilename,ios::binary|ios::in);
    if(inFile.good())
    {
    
    
        inFile.close();
        return true;
    }
    else
        return false;
}

void DBaseFile:: readFileHead(ifstream& inFile)
{
    
    
    if(!isReadFileOK(_sFilename))
        return;
    // 读取文件头中的记录条数,即行数
    inFile.seekg(4,ios::beg);
    inFile.read((char*)&_iRecCount,sizeof (int));

    // 读取文件头的字节数
    inFile.read((char*)&_BytesOfFileHead,sizeof (short));

    // 读取一条记录中的字节长度
    inFile.read((char*)&_BytesOfEachRecord,sizeof (short));

    // 计算字段数,即列数
    _iFieldCount = (_BytesOfFileHead-33)/32;

    // 开始读取文件头中关于字段的描述
    for(int i=0;i<_iFieldCount;i++)
    {
    
    
        inFile.seekg(32+32*i,ios::beg);
        _pField=new Field;
        for(int j=0;j<11;j++)   // 读取字段名,存入_cTitle数组
            inFile.read(_pField->_cTitle+j,sizeof (char));
        inFile.read(&_pField->_cDataType,sizeof (char));    // 读取字段的数据类型并存入_cDataType
        inFile.seekg(4,ios::cur);
        inFile.read((char*)&_pField->_ucFieldLength,sizeof (char));    // 读取字段长度,此时的字段长度为BYTE类型,需通过强制类型转换成int型

        _vTable.push_back(_pField);
    }
}

void DBaseFile:: readFileRecord(ifstream& inFile)
{
    
    
    inFile.seekg(_BytesOfFileHead,ios::beg);
    char cDeleteTag;
    for(int i=0;i<_iRecCount;i++)
    {
    
    
        inFile.read(&cDeleteTag,sizeof (char));
        for(unsigned int j=0;j<_vTable.size();j++)
        {
    
    
            char*cRecord=new char[(int)_vTable[j]->_ucFieldLength];
            for(int k=0;k<(int)_vTable[j]->_ucFieldLength;k++)
                inFile.read(cRecord+k,sizeof (char));
            _vTable[j]->_vField.push_back(cRecord);
        }
    }
}

void DBaseFile:: addRec(int iColum, int iLine, unsigned char* ucData)
{
    
    }

void DBaseFile:: deleteRec(int iColum, int iLine, unsigned char* ucData)
{
    
    }

void DBaseFile:: modifyRec(int iColum, int iLine, unsigned char* ucData)
{
    
    }

void DBaseFile:: checkRec(int iColum, int iLine, unsigned char* ucData)
{
    
    }

to sum up

This article starts from the DBF file format, abstract Field class and DBaseFile class, the code has a certain degree of versatility, for DBF files under normal circumstances, the code in this article can be read. However, this article only reads the DBF file into the memory, and does not involve the write operation of the file, so it has certain limitations. But for the DBF file format, the code in this article can help readers understand.

Guess you like

Origin blog.csdn.net/GeomasterYi/article/details/106635440