Matlab 直接读取二进制文件
本文作者原创。
matlab可以直接读取二进制数据文件,并且可以将其加入到矩阵中。以充分利用matlab快速处理矩阵的优势。
matlab读取二进制文件,涉及到的函数包括
fopen,fclose,ftell,fseek,fread,fwrite,feof
一、文件打开和关闭
1、打开文件
在读写文件之前,必须先用fopen函数打开或创建文件,并指定对该文件进行的操作方式
fopen函数
调用格式:fid=fopen(文件名,‘打开方式’)
说明:其中fid用于存储文件句柄值,如果返回的句柄值大于0,则说明文件打开成功。文件名用字符串形式,表示待打开的数据文件。常见的打开方式如下:
‘r’:只读方式打开文件(默认的方式),该文件必须已存在。
‘r+’:读写方式打开文件,打开后先读后写。该文件必须已存在。
‘w’:打开后写入数据。该文件已存在则更新;不存在则创建。
‘w+’:读写方式打开文件。先读后写。该文件已存在则更新;不存在则创建。
‘a’:在打开的文件末端添加数据。文件不存在则创建。
‘a+’:打开文件后,先读入数据再添加数据。文件不存在则创建。
另外,在这些字符串后添加一个“t”,如‘rt’或‘wt+’,则将该文件以文本方式打开;如果添加的是“b”,则以二进制格式打开,这也是fopen函数默认的打开方式。
2、关闭文件
文件在进行完读、写等操作后,应及时关闭,以免数据丢失。
fclose函数,
调用格式为:sta=fclose(fid)
说明:该函数关闭fid所表示的文件。sta表示关闭文件操作的返回代码,若关闭成功,返回0,否则返回-1。如果要关闭所有已打开的文件用fclose(‘all’)。
二、二进制文件的读写操作
1、写二进制文件
fwrite函数
按照指定的数据精度将矩阵中的元素写入到文件中。其调用格式为:
COUNT=fwrite(fid,A,precision)
说明:其中COUNT返回所写的数据元素个数(可缺省),fid为文件句柄,A用来存放写入文件的数据,precision代表数据精度,常用的数据精度有:char、uchar、int、long、float、double等。缺省数据精度为uchar,即无符号字符格式。
2、读二进制文件
fread函数可以读取二进制文件的数据,并将数据存入矩阵。其调用格式为:
[A,COUNT]=fread(fid,size,precision)
说明:其中A是用于存放读取数据的矩阵、COUNT是返回所读取的数据元素个数、fid为文件句柄、size为可选项,若不选用则读取整个文件内容;若选用则它的值可以是下列值:N(读取N个元素到一个列向量)、inf(读取整个文件)、[M,N](读数据到M×N的矩阵中,数据按列存放)。precision用于控制所写数据的精度,其形式与fwrite函数相同。
三、应用matlab表功能直接读取通达信K线文件文件
通达信专业版以上会有后台数据到处功能,通过txt文件的方式供其它软件使用。但这里采用的是利用matlab强大的文件功能直接读取通达信的后台数据文件。
通达信后台数据文件K部分主要存放在vipdoc文件夹里,子目录分别存放在sh(上交所)、sz(深交所)下的lday(日线)、fzline(5分钟线)、minline下,扩展名分别为day(日线)、lc5(5分钟)、lc1(1分钟)。
1、通达信日线*.day文件
文件名即股票代码
每32个字节为一天数据
每4个字节为一个字段,每个字段内低字节在前
00 ~ 03 字节:年月日, 32位整型
04 ~ 07 字节:开盘价*100, 32位整型
08 ~ 11 字节:最高价*100, 32位整型
12 ~ 15 字节:最低价*100, 32位整型
16 ~ 19 字节:收盘价*100, 32位整型
20 ~ 23 字节:成交额(元),float型
24 ~ 27 字节:成交量(股),32位整型
28 ~ 31 字节:预留
2、通达信5分钟线*.lc5文件和1分钟线*.lc1
文件名即股票代码
每32个字节为一个5分钟数据,每字段内低字节在前
00 ~ 01 字节:日期,整型,设其值为num,则日期计算方法为:
year=floor(num/2048)+2004;
month=floor(mod(num,2048)/100);
day=mod(mod(num,2048),100);
02 ~ 03 字节: 从0点开始至目前的分钟数,整型
04 ~ 07 字节:开盘价,单精度浮点数
08 ~ 11 字节:最高价,单精度浮点数
12 ~ 15 字节:最低价,单精度浮点数
16 ~ 19 字节:收盘价,单精度浮点数
20 ~ 23 字节:成交额*100,float型
24 ~ 27 字节:成交量(股),整型
28 ~ 31 字节:(保留)
本实例针对日线和分钟线分别做成两个读取函数,读取的数据存放在matlab的table文件,存储为.Mat,方便下次调用。由于每只股票一个文件,需要采用严格的目录管理加以管理。
function readday(infile)
%%
%{读取通达信盘后日线数据
% 文件名:股票代码
% 每32个字节为一个日线数据,每字段内低字节在前
% 00 ~ 03 字节:日期,整型;
% 04 ~ 07 字节:开盘价,整型
% 08 ~ 11 字节:最高价,整型
% 12 ~ 15 字节:最低价,整型
% 16 ~ 19 字节:收盘价,整型
% 20 ~ 23 字节:成交额,float型
% 24 ~ 27 字节:成交量(股),整型
% 28 ~ 31 字节:(保留)%}
tic
MainPath = ‘\\Stock’;
DataBasePath = '\\DataBasePath';
lx = infile(end-2:end);
fn = infile(1:end-4);
if strcmp(lx,'day')
p = ['D:\\',MainPath,DataBasePath,'\\Daily\\',fn,'.mat'];
else
return;
end;
fid=fopen(infile,'r');
fseek(fid,0,'bof');
clear lc5
ps=fread(fid,[8,inf],'int32'); %读按每个数据4个字节取全部数据,,精度为int32
%取其中的日期和开盘、最高、最低、收盘、成交量,
ps = ps';
year = num2str(floor(ps(:,1)/10000)); %提取年信息
mon = num2str(floor(mod(ps(:,1),10000)/100),'d'); %提取月信息
day = num2str(mod(mod(ps(:,1),10000),100),'d'); %提取日信息
n = length(year);
for i = 1:n
dstr(i,:) = [year(i,:),'-',mon(i,:),'-',day(i,:)];
end;
fseek(fid,0,'bof');
ps1=fread(fid,[8,inf],'single'); %读按每个数据取4个字节取全部数据,,精度为单精度浮点型
%取其中的成交额,
ps1 = ps1';
colName = {'date','open','high','low','close','volume','amount'};
dayl =
table(dstr,ps(:,2)./100,ps(:,3)./100,ps(:,4)./100,ps(:,5)./100,ps(:,7),ps1(:,6),'VariableNames',colName);
fclose(fid);
eval_r([fn,' = dayl']);
save (p,fn);
toc
function readlc(infile)
%%
%{读取通达信盘后分钟数据
% 文件名:股票代码
% 每32个字节为一个分钟数据,每字段内低字节在前
% 00 ~ 01 字节:日期,整型,设其值为num,则日期计算方法为:
% year=floor(num/2048)+2004;
% month=floor(mod(num,2048)/100);
% day=mod(mod(num,2048),100);
% 02 ~ 03 字节: 从0点开始至目前的分钟数,整型
% 04 ~ 07 字节:开盘价,single
% 08 ~ 11 字节:最高价,single
% 12 ~ 15 字节:最低价,single
% 16 ~ 19 字节:收盘价,single
% 20 ~ 23 字节:成交额*100,float型
% 24 ~ 27 字节:成交量(股),整型
% 28 ~ 31 字节:(保留)%}
MainPath = ‘\\Stock’;
DataBasePath = '\\DataBasePath';
lx = infile(end-2:end);
fn = infile(1:end-4);
if strcmp(lx,'lc1')
p = ['D:\\',MainPath,DataBasePath,'\\Min\\',fn,'.mat'];
elseif strcmp(lx,'lc5')
p = ['D:\\',MainPath,DataBasePath,'\\5Min\\',fn,'.mat'];
else
return;
end;
fid=fopen(infile,'r');
fseek(fid,0,'bof');
clear lc5
date=fread(fid,[16,inf],'uint16'); %读按每个数据取2个字节取全部数据,,精度为uint16
%取其中日期和时间数据
date = date';
year = num2str(floor(date(:,1)/2048)+2004); %提取年信息
mon = num2str(floor(mod(date(:,1),2048)/100),'d'); %提取月信息
day = num2str(mod(mod(date(:,1),2048),100),'d'); %提取日信息
n = length(year);
for i = 1:n
dstr(i,:) = [year(i,:),'-',mon(i,:),'-',day(i,:)];
end;
tm=floor(date(:,2)/60)*100+mod(date(:,2),60); %转为几点(千、百位)几分(十、个位)
fseek(fid,0,'bof');
ps=fread(fid,[8,inf],'single'); %读按每个数据取4个字节取全部数据,,精度为单精度浮点型
%取其中的开盘、最高、最低、收盘、成交额,
ps = ps';
fseek(fid,0,'bof');
ps2=fread(fid,[8,inf],'int32'); %读按每个数据取4个字节取全部数据,,精度为int32
%只取其中的成交量数据,
ps2=ps2';
colName = {'dat','time','open','high','low','close','volume','amount'}
lc
table(dstr,tm,ps(:,2),ps(:,3),ps(:,4),ps(:,5),ps2(:,7),ps(:,6),'VariableNames',colName);
=
fclose(fid);
eval_r([fn,' = lc']);
save (p,fn);
由于matlab不能直接读取结构数据,本实例根据不同数据精度多次读取到数组的方法,由于每次读取数据实际上是在内存中进行,并不会太大影响读取速度。比for循环逐条读取速度快得多。当如果网友有更好办法,欢迎留言。
使用该实例的时候,注意源文件的路径。