通达信V6概念板块分类文件格式分析
文件位置
/jcb_zxjt/T0002/hq_cache/ block.dat
数据格式
(1)、文件头部信息
数据含义 | 数据类型 | 备注 |
文件信息 | Char[64] |
|
板块索引信息起始位置 | Integer |
|
板块记录信息起始位置 | Integer |
|
未知 | Integer * 3 |
|
(2)、板块索引信息,开始于0x0054h
数据含义 | 数据类型 | 备注 |
索引名称 | Char[64] |
|
未知 | Integer * 9 |
|
注意:
1)、每个板块索引信息占的长度为100个字节。
(3)、板块记录信息,开始于0x0180h
数据含义 | 数据类型 | 备注 |
板块数量 | word | 起始位置为0x180h |
板块记录结构
数据含义 | 数据类型 | 备注 |
板块名称 | Char [9] |
|
证券数量 | word |
|
板块级别 | word |
|
证券代码 | Char [7] * 400 |
|
注意:
1)、第一个版块的起始位置为0x182h。
2)、每个板块占的长度为2813个字节。
3)、每个板块最多包括400只股票。(2813 -9 - 2 - 2) / 7 = 400
示例代码
示例:显示板块数据文件信息
单元:uDataBuffer
备注:uDataBuffer单元代码在“大智慧Level2日线数据文件格式分析”文档中。
单元:uBlockData
unit uBlockData;
interface
uses
uDataBuffer;
type
TFileHead_Block = packed record
FileInfo: array[0..63] of char; //--文件信息
BlockIndexStart: Integer; //--板块索引信息起始位置
BlockDataStart: Integer; //--板块记录信息起始位置
Unknown: array[0..2] of Integer; //--未知
end;
PFileHead_Block = ^TFileHead_Block;
TIndexRecord_Block = packed record
IndexName: array[0..63] of char; //--索引名称
Unknown: array[0..8] of Integer; //--未知
end;
PIndexRecord_Block = ^TIndexRecord_Block;
TStockCode = array[0..6] of char;
TDataRecord_Block = packed record
BlockName: array[0..8] of char; //--板块名称
StockCount: word; //--证券数量
BlockLevel: word; //--板块级别
StockCodes: array[0..399] of TStockCode; //--证券代码
end;
PDataRecord_Block = ^TDataRecord_Block;
TStockDataStream_Block = class(TCustomStringBuffer)
private
FFileHead: TFileHead_Block;
FIndexCount: Integer;
FIndexSize: Integer;
FDataCount: word;
FDataSize: Integer;
function GetDatas(Index: Integer): PDataRecord_Block;
function GetHead: PFileHead_Block;
function GetIndexs(Index: Integer): PIndexRecord_Block;
protected
procedure ClearBuffer; override;
procedure DoBufferChange; override;
public
constructor Create;
//---
property Head: PFileHead_Block read GetHead;
property Datas[Index: Integer]: PDataRecord_Block read GetDatas;
property DataCount: word read FDataCount;
property Indexs[Index: Integer]: PIndexRecord_Block read GetIndexs;
property IndexCount: Integer read FIndexCount;
end;
implementation
constructor TStockDataStream_Block.Create;
begin
inherited;
//---
FIndexSize := sizeof(TIndexRecord_Block);
FDataSize := sizeof(TDataRecord_Block);
end;
procedure TStockDataStream_Block.ClearBuffer;
begin
inherited;
//---
FIndexCount := 0;
FDataCount := 0;
end;
procedure TStockDataStream_Block.DoBufferChange;
//---
function _ReadFileHead: Boolean;
begin
Result := self.BufferSize >= SizeOf(FFileHead);
if Result then
Move(self.Buffer^,FFileHead,SizeOf(FFileHead));
end;
//---
function _ReadIndex: Boolean;
var
ABlockIndexLen: integer;
begin
Result := self.BufferSize >= FFileHead.BlockDataStart;
if Result then
begin
ABlockIndexLen := (FFileHead.BlockDataStart - FFileHead.BlockIndexStart);
FIndexCount := ABlockIndexLen div FIndexSize;
//---
Result := ABlockIndexLen = FIndexSize * FIndexCount;
end;
end;
//---
function _ReadData: Boolean;
//---
function _GetDataCount: Boolean;
var
p: Pchar;
begin
Result := self.BufferSize >= FFileHead.BlockDataStart + SizeOf(FDataCount);
if Result then
begin
p := self.Buffer;
inc(p,FFileHead.BlockDataStart);
Move(p^,FDataCount,SizeOf(FDataCount));
//---
Result := FDataCount > 0;
end;
end;
//---
function _CheckDataLen: Boolean;
begin
Result := self.BufferSize = FFileHead.BlockDataStart + SizeOf(FDataCount) + FDataSize * FDataCount;
end;
begin
Result := _GetDataCount and _CheckDataLen;
end;
begin
inherited;
//---
if FDataSize <= 0 then
self.ClearBuffer
else
begin
if not (_ReadFileHead and _ReadIndex and _ReadData) then
self.ClearBuffer;
end;
end;
function TStockDataStream_Block.GetDatas(Index: Integer): PDataRecord_Block;
begin
Result := Pointer(self.Buffer + FFileHead.BlockDataStart + SizeOf(FDataCount) + FDataSize * Index);
end;
function TStockDataStream_Block.GetHead: PFileHead_Block;
begin
Result := @FFileHead;
end;
function TStockDataStream_Block.GetIndexs(Index: Integer): PIndexRecord_Block;
begin
Result := Pointer(self.Buffer + FFileHead.BlockIndexStart + FIndexSize * Index);
end;
end.
单元:Unit1
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;
RadioGroup1: TRadioGroup;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure ShowData_Block(const AFile: string; const AListBox: TListBox);
public
procedure ShowData(const AFile: string; const AListBox: TListBox);
end;
var
Form1: TForm1;
implementation
uses uDayData,uCacheDayData,uZstData,uBlockData;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
with RadioGroup1.Items do
begin
clear;
Add('概念板块数据');
end;
RadioGroup1.ItemIndex := 0;
//---
SendMessage(ListBox1.Handle,LB_SetHorizontalExtent,2000,longint(0));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
with self.OpenDialog1 do
begin
if Execute then
self.ShowData(FileName,ListBox1);
end;
end;
procedure TForm1.ShowData(const AFile: string; const AListBox: TListBox);
begin
case RadioGroup1.ItemIndex of
0: ShowData_Block(AFile,AListBox);
end;
end;
procedure TForm1.ShowData_Block(const AFile: string;
const AListBox: TListBox);
var
AStream: TStockDataStream_Block;
//---
procedure _ShowHead;
var
i: integer;
begin
with AListBox.Items,AStream.Head^ do
begin
Add(Format('文件信息:%s', [FileInfo]));
Add(Format('板块索引起始位置:%d', [BlockIndexStart]));
Add(Format('板块记录起始位置:%d', [BlockDataStart]));
//---
for i := low(Unknown) to high(Unknown) do
Add(Format('未知:%d', [Unknown[i]]));
end;
end;
//---
procedure _ShowIndex;
var
j,AIndex: Integer;
begin
with AListBox.Items,AStream do
begin
Add('--------索引---------');
//---
for AIndex := 0 to IndexCount - 1 do
begin
with Indexs[AIndex]^ do
begin
Add(Format('索引名称:%s', [IndexName]));
//---
for j := low(Unknown) to high(Unknown) do
Add(Format('未知:%d', [Unknown[j]]));
end;
end;
end;
end;
//---
procedure _ShowData;
var
ABlockIndex,AStockIndex: Integer;
begin
with AListBox.Items,AStream do
begin
Add('--------板块---------');
//---
Add(Format('板块数量:%d', [DataCount]));
if DataCount > 0 then
Add(Format('板块数据大小:%d', [sizeof(Datas[ABlockIndex]^) * DataCount]));
Add(' ');
//---
for ABlockIndex := 0 to DataCount - 1 do
begin
with Datas[ABlockIndex]^ do
begin
Add(Format('板块%d 板块名称:%s 证券数量:%d 板块级别:%d', [ABlockIndex + 1,BlockName,StockCount,BlockLevel]));
for AStockIndex := low(StockCodes) to high(StockCodes) do
Add(Format('%.3d 代码:%s', [AStockIndex + 1,StockCodes[AStockIndex]]));
end;
end;
end;
end;
begin
AStream := TStockDataStream_Block.Create;
try
with AListBox.Items do
begin
BeginUpdate;
Clear;
with AStream do
begin
if ReadFile(AFile) then
begin
_ShowHead;
_ShowIndex;
_ShowData;
end;
end;
EndUpdate;
end;
finally
AStream.Free;
end;
end;
end.