股票DBF文件格式

1、行情文件说明

沪市行情文件show2003.dbf

深市行情文件sjshq.dbf

 

2、行情文件格式

说明:

1)、表文件由头记录及数据记录组成。头记录定义该表的结构及与表相关的其他信息。数据记录紧接在头记录之后,包含字段中实际的文本。记录的长度等于所有字段定义的长度之和(以字节为单位)。

2)、头记录以终止符(0x0D)结束,数据记录以终止符(0x1A)结束。

3)、表文件中存储整数时低位字节在前。

4)、数据记录从删除标记字节开始。如果删除标记字节为 ASCII 空格 (0x20),则表示该记录未被删除,如果该字节为星号 (0x2A),则表示该记录被删除。在删除标记之后是字段记录中所命名的各字段的数据。

5)、数据记录都是用ASCII码形式存放的,所以只要读出文件头和字段类型描述区的内容,就可以直接读取dbf文件中的每条记录。

 

文件头部结构(32字节)

位置

长度

含义

备注

0

1

文件类型

0x03FoxBASE+/dBASE III PLUS,无备注

1 - 3

3

最近一次更新的时间(YYMMDD

 

4 - 7

4

文件中的记录数目

 

8 - 9

2

文件中的第一个数据记录的位置

 

10 - 11

2

每个数据记录的长度(包括删除标记)

 

12 - 31

20

保留

 

 

 

字段记录结构(32字节)  

位置

长度

说明

备注

0 - 10

11

字段名

最多10个字符,若少于10则用空字符填充

11

1

字段类型

C-字符型

Y-货币型

N-数值型

F-浮点型

D-日期型

T-日期时间型

B-双精度型

I-整型

L-逻辑型

M-备注型

G-通用型

C-字符型(二进制)

M-备注型(二进制)

P-图片型

12 - 15

4

记录中该字段的偏移量(16进制)

 

16

1

字段长度

以字节为单位

17

1

小数位数

以字节为单位

18 - 31

14

保留

 

 

 

示例代码

示例:显示DBF文件信息

说明:delphi编写的示例,显示DBF文件中头部信息、字段信息和数据信息。

 

unit uDataBuffer;

 

interface

 

uses

    SysUtils,Classes;

 

type

    TCustomStringBuffer = class(TObject)

    private

        FBuffer: PChar;

        FBufferSize: Integer;

        FBufferContent: string;

        function GetBufferContent: string;

        procedure SetBufferSize(Value: Integer);

        procedure SetBufferContent(const Value: string);

    protected

        procedure DoBufferChange; virtual;

        procedure ClearBuffer; virtual;

    public

        constructor Create;

        //---

        function ReadFile(const AFileName: string): Boolean;

        function SaveFile(const AFileName: string; const Append: Boolean = false):

            Boolean;

        //---

        property Buffer: PChar read FBuffer;

        property BufferSize: Integer read FBufferSize write SetBufferSize;

        property BufferContent: string read GetBufferContent write SetBufferContent;

    end;

    TRecordStream = class(TCustomStringBuffer)

    private

        FCount: Integer;

        FDataSize: Cardinal;

        function GetDatas(Index: Integer): Pointer;

        procedure SetCount(const Value: Integer);

    protected

        procedure ClearBuffer; override;

        procedure DoBufferChange; override;

        //---

        property Datas[Index: Integer]: Pointer read GetDatas;

        property DataSize: Cardinal read FDataSize write FDataSize;

    public

        property Count: Integer read FCount write SetCount;

    end;

 

function OpenToFile(const AFileName: string; const AMode: Integer; const AIsAppend: Boolean = false): integer;

function ReadFormFile(const AFileName: string): string;

function SaveToFile(const AFileName,AContent: string; const AIsAppend: Boolean

    = false): Boolean;

 

implementation

 

function OpenToFile(const AFileName: string; const AMode: Integer; const AIsAppend: Boolean = false): integer;

const

    CNT_OpenCount = 20;

    CNT_OpenOutTime = 30;

    //---

    function _OpenWrite: integer;

    var

        i,AFileHandle: integer;

        APath: string;

    begin

        if FileExists(AFileName) then

        begin

            for i := 0 to CNT_OpenCount do

            begin

                if AIsAppend then

                    AFileHandle := FileOpen(AFileName,fmOpenWrite or fmShareExclusive)

                else

                    AFileHandle := FileCreate(AFileName);

                if AFileHandle < 0 then

                    sleep(CNT_OpenOutTime)

                else

                    Break;

            end;

        end

        else

        begin

            APath := ExtractFilePath(AFileName);

            if not DirectoryExists(APath) then

                ForceDirectories(APath);

            //---

            AFileHandle := FileCreate(AFileName);

        end;

        //---

        Result := AFileHandle;

    end;

    //---

    function _OpenRead: integer;

    var

        i,AFileHandle: integer;

    begin

        Result := -1;

        //---

        if not FileExists(AFileName) then

            Exit;

        //---

        for i := 0 to CNT_OpenCount do

        begin

            AFileHandle := FileOpen(AFileName,fmOpenRead or fmShareDenyNone);

            if AFileHandle < 0 then

                sleep(CNT_OpenOutTime)

            else

                Break;

        end;

        //---

        Result := AFileHandle;

    end;

begin

    Result := -1;

    //---

    if Trim(AFileName) = '' then

        Exit;

    //---

    if AMode = fmOpenWrite then

        Result := _OpenWrite

    else

        Result := _OpenRead;

end;

 

function ReadFormFile(const AFileName: string): string;

var

    AFileHandle,ABufferSize: integer;

begin

    Result := '';

    //---

    AFileHandle := OpenToFile(AFileName,fmOpenRead);

    if AFileHandle < 0 then

        Exit;

    //---

    try

        ABufferSize := FileSeek(AFileHandle,0,soFromEnd);

        if ABufferSize = 0 then

            Exit;

        //---

        SetLength(Result,ABufferSize);

        //---

        FileSeek(AFileHandle,0,soFromBeginning);

        FileRead(AFileHandle,Pchar(Result)^,ABufferSize);

    finally

        FileClose(AFileHandle);

    end;

end;

 

function SaveToFile(const AFileName,AContent: string; const AIsAppend: Boolean

    = false): Boolean;

var

    AFileHandle: integer;

begin

    result := false;

    //---

    if Length(AContent) = 0 then

        Exit;

    //---

    try

        AFileHandle := OpenToFile(AFileName,fmOpenWrite,AIsAppend);

        if AFileHandle < 0 then

            Exit;

        //---

        try

            if AIsAppend then

                FileSeek(AFileHandle,0,soFromEnd)

            else

                FileSeek(AFileHandle,0,soFromBeginning);

            FileWrite(AFileHandle,Pchar(AContent)^,Length(AContent));

        finally

            FileClose(AFileHandle);

        end;

        //---

        Result := true;

    except

        on E: Exception do

        begin

            Result := false;

        end;

    end;

end;

 

procedure TCustomStringBuffer.ClearBuffer;

begin

    FBufferSize := 0;

end;

 

constructor TCustomStringBuffer.Create;

begin

    FBufferSize := 0;

end;

 

procedure TCustomStringBuffer.DoBufferChange;

begin

    FBuffer := PChar(FBufferContent);

end;

 

function TCustomStringBuffer.GetBufferContent: string;

begin

    if FBufferSize = 0 then

        Result := ''

    else

        Result := FBufferContent;

end;

 

function TCustomStringBuffer.ReadFile(const AFileName: string): Boolean;

begin

    self.BufferContent := ReadFormFile(AFileName);

    Result := self.BufferSize > 0;

end;

 

function TCustomStringBuffer.SaveFile(const AFileName: string; const Append:

    Boolean = false): Boolean;

begin

    result := SaveToFile(AFileName,self.BufferContent,Append);

end;

 

procedure TCustomStringBuffer.SetBufferSize(Value: Integer);

begin

    FBufferSize := Value;

    if FBufferSize < 0 then

        FBufferSize := 0;

    //---

    if FBufferSize > 0 then

        SetLength(FBufferContent,Value);

    //---

    DoBufferChange;

end;

 

procedure TCustomStringBuffer.SetBufferContent(const Value: string);

begin

    FBufferContent := Value;

    FBufferSize := Length(FBufferContent);

    //---

    DoBufferChange;

end;

 

procedure TRecordStream.ClearBuffer;

begin

    inherited;

    //---

    FCount := 0;

end;

 

procedure TRecordStream.DoBufferChange;

    //---

    procedure _RefreshCount;

    begin

        FCount := FBufferSize div FDataSize;

        if FDataSize * FCount <> FBufferSize then

            self.ClearBuffer;

    end;

begin

    inherited;

    //---

    if FDataSize <= 0 then

        self.ClearBuffer

    else

        _RefreshCount;

end;

 

function TRecordStream.GetDatas(Index: Integer): Pointer;

begin

    Result := FBuffer + Index * FDataSize;

end;

 

procedure TRecordStream.SetCount(const Value: Integer);

begin

    FCount := Value;

    if FCount < 0 then

        FCount := 0;

    //---

    self.BufferSize := FDataSize * FCount;

end;

 

end.

 

unit uStockDbfData;

 

interface

 

uses

    uDataBuffer;

 

type

    TDbfHead = packed record

        FileKind: byte; //--文件类型

        FileDate: array[0..2] of byte; //--文件更新时间(YYMMDD

        RecordCount: Cardinal; //--记录数目

        RecordStart: Word; //--文件第一个记录的起始位置

        RecordLength: Word; //--记录长度(包括删除标记)

        Reserve: array[0..19] of Char; //--保留

    end;

    PTDbfHead = ^TDbfHead;

 

    TDbfField = packed record

        Name: array[0..10] of Char; //--字段名

        Kind: Char; //--字段类型

        Start: Cardinal; //--记录中该字段的偏移量(16进制)

        Len: byte; //--字段长度

        Decimal: byte; //--小数位数

        Reserve: array[0..13] of Char; //--保留

    end;

    TDbfFields = array of TDbfField;

 

    TDbfRecordStream = class(TRecordStream)

    private

        function GetItems(Index: Integer): string;

    public

        property Items[Index: Integer]: string read GetItems; default;

    end;

 

    TStockDbfStream = class(TCustomStringBuffer)

    private

        FHead: TDbfHead;

        FFields: TDbfFields;

        FRecords: TDbfRecordStream;

        function GetHead: PTDbfHead;

    protected

        procedure DoBufferChange; override;

    public

        constructor Create;

        destructor Destroy; override;

        //---

        function GetFieldValue(const ARecord: string; const AFieldIndex: integer): string;

        //---

        property Head: PTDbfHead read GetHead;

        property Fields: TDbfFields read FFields;

        property Records: TDbfRecordStream read FRecords;

    end;

 

implementation

 

constructor TStockDbfStream.Create;

begin

    inherited;

    //---

    FRecords := TDbfRecordStream.Create;

end;

 

destructor TStockDbfStream.Destroy;

begin

    FRecords.Free;

    //---

    inherited;

end;

 

procedure TStockDbfStream.DoBufferChange;

const

    CNT_HeadSize = $00018;

    CNT_DataStartAddress = $41000;

    //---

    function _ReadHead(var AReadSize: integer): Boolean;

    begin

        Result := self.BufferSize - AReadSize > SizeOf(FHead);

        if Result then

        begin

            Move(Buffer^,FHead,SizeOf(FHead));

            AReadSize := SizeOf(FHead);

        end;

    end;

    //---FHead.RecordStart = 文件头部大小(32个字节) + 字段信息大小 + 终止符大小(1个字节)

    function _ReadFields(var AReadSize: integer): Boolean;

    var

        AFieldBufferSize,AFieldCount: integer;

    begin

        AFieldBufferSize := FHead.RecordStart - AReadSize - 1;

        AFieldCount := AFieldBufferSize div sizeof(TDbfField);

        if sizeof(TDbfField) * AFieldCount <> AFieldBufferSize then

            AFieldCount := 0;

        //---

        Result := AFieldCount > 0;

        if Result then

        begin

            setlength(FFields,AFieldCount);

            Move((Buffer + AReadSize)^,FFields[0],AFieldBufferSize);

            //---

            AReadSize := FHead.RecordStart;

        end;

    end;

    //---

    function _ReadRecords(var AReadSize: integer): Boolean;

    var

        ARecordBuffer: string;

        ARecordBufferSize: integer;

    begin

        with FHead do

            ARecordBufferSize := RecordLength * RecordCount;

        //---

        Result := ARecordBufferSize <= (self.BufferSize - AReadSize);

        if Result then

        begin

            setlength(ARecordBuffer,ARecordBufferSize);

            Move((Buffer + AReadSize)^,ARecordBuffer[1],ARecordBufferSize);

            //---

            with FRecords do

            begin

                DataSize := FHead.RecordLength;

                BufferContent := ARecordBuffer;

            end;

        end;

    end;

    //---

var

    AReadSize: integer;

begin

    inherited;

    //---

    FillChar(FHead,SizeOf(FHead),0);

    setlength(FFields,0);

    FRecords.Count := 0;

    //---

    AReadSize := 0;

    if not (_ReadHead(AReadSize) and _ReadFields(AReadSize) and _ReadRecords(AReadSize)) then

        self.ClearBuffer;

end;

 

function TStockDbfStream.GetFieldValue(const ARecord: string;

    const AFieldIndex: integer): string;

var

    AData:string;

begin

    //---数据记录的第1个字节为删除标记,空格 (0x20) -> 未删除,星号 (0x2A) -> 删除

    AData := Copy(ARecord,2,Length(ARecord) - 1);

    //---

    with FFields[AFieldIndex] do

        Result := Copy(AData,Start,Len);

end;

 

function TStockDbfStream.GetHead: PTDbfHead;

begin

    Result := @FHead;

end;

 

function TDbfRecordStream.GetItems(Index: Integer): string;

var

    ARecord: string;

begin

    setlength(Result,DataSize);

    Move((Buffer + Index * DataSize)^,PChar(Result)^,DataSize);

    //---

    //Result := Copy(BufferContent,Index * DataSize + 1,DataSize);

end;

 

end.

 

unit Unit1;

 

interface

 

uses

    Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,

    Dialogs,StdCtrls,ExtCtrls;

 

type

    TForm1 = class(TForm)

        Button1: TButton;

        ListBox1: TListBox;

        GroupBox1: TGroupBox;

        OpenDialog1: TOpenDialog;

        Panel1: TPanel;

        procedure FormCreate(Sender: TObject);

        procedure Button1Click(Sender: TObject);

    private

        procedure ShowData(const AFile: string; const AListBox: TListBox);

    end;

 

var

    Form1: TForm1;

 

implementation

 

uses uStockDbfData;

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

    SendMessage(ListBox1.Handle,LB_SetHorizontalExtent,2000,longint(0));

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

    with self.OpenDialog1 do

    begin

        if Execute then

            ShowData(FileName,ListBox1);

    end;

end;

 

procedure TForm1.ShowData(const AFile: string; const AListBox: TListBox);

var

    AStream: TStockDbfStream;

    //---

    procedure _ShowHead;

    begin

        with AListBox.Items,AStream.Head^ do

        begin

            Add('--------文件头部---------');

            Add(Format('文件类型:%d  文件更新时间:%d.%d.%d  记录数目:%d  记录起始位置:%d  记录长度:%d',

                [FileKind,FileDate[0],FileDate[1],FileDate[2],RecordCount,RecordStart,RecordLength]));

        end;

    end;

    //---

    procedure _ShowFields;

    var

        i: Integer;

    begin

        with AListBox.Items,AStream do

        begin

            Add('--------字段信息---------');

            //---

            for i := low(Fields) to high(Fields) do

            begin

                with Fields[i] do

                begin

                    Add(Format('字段名:%s  字段类型:%s  字段的偏移量:%d  字段长度:%d  小数位数:%d',

                        [Name,Kind,Start,Len,Decimal]));

                end;

            end;

        end;

    end;

    //---

    {procedure _ShowRecords;

    var

        i: Integer;

    begin

        with AListBox.Items,AStream do

        begin

            Add('--------记录信息---------');

            //---

            for i := 0 to Records.Count - 1 do

                Add(Records[i]);

        end;

    end;}

    //---

    procedure _ShowRecords;

    var

        i,j: Integer;

        AText: string;

    begin

        with AListBox.Items,AStream do

        begin

            Add('--------记录信息---------');

            //---

            for i := 0 to Records.Count - 1 do

            begin

                AText := '';

                for j := low(Fields) to high(Fields) do

                    AText := AText + '  ' + GetFieldValue(Records[i],j);

                //---

                Add(AText);

            end;

        end;

    end;

begin

    AStream := TStockDbfStream.Create;

    try

        with AListBox.Items do

        begin

            BeginUpdate;

            Clear;

            with AStream do

            begin

                if ReadFile(AFile) then

                begin

                    _ShowHead;

                    _ShowFields;

                    _ShowRecords;

                end;

            end;

            EndUpdate;

        end;

    finally

        AStream.Free;

    end;

end;

 

end.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值