我联系了DBFREAD函数的作者Brian Madsen,该函数被从文件交换中删除,可能是因为The Mathworks将在未来的某个版本中将此函数包含到MATLAB中。 Brian很慷慨地允许我在这里发布这个函数。版权信息保持不变。 我只修改了33-38行,以允许DBFREAD读取工作目录外的文件。
function [dbfData, dbfFieldNames] = dbfread(filename, records2read, requestedFieldNames)
[pathstr,name,ext] = fileparts(filename);
dbfFileId = fopen(filename,'r','ieee-le');
if (dbfFileId == -1)
dbfFileId = fopen(fullfile(pathstr, [name '.dbf']),'r','ieee-le');
end
if (dbfFileId == -1)
dbfFileId = fopen(fullfile(pathstr, [name '.DBF']),'r','ieee-le');
end
if (dbfFileId == -1)
eid = sprintf('MATLAB:%s:missingDBF', mfilename);
msg = sprintf('Failed to open file %s.dbf or file %s.DBF.',...
name, name);
error(eid,'%s',msg)
end
info = dbfinfo(dbfFileId);
if ~exist('requestedFieldNames','var')
dbfFieldNames = {info.FieldInfo.Name};
requestedFieldNames = dbfFieldNames;
else
dbfFieldNames = (info.FieldInfo(matchFieldNames(info,requestedFieldNames)).Name);
end
fields2read = matchFieldNames(info,requestedFieldNames);
lengthOfDeletionIndicator = 1;
if ~exist('records2read','var')
records2read = (1:info.NumRecords);
elseif max(records2read) > info.NumRecords
eid = sprintf('MATLAB:%s:invalidRecordNumber', mfilename);
msg = sprintf('Record number %d does not exist, please select from the range 1:%d.',...
max(records2read), info.NumRecords);
error(eid,'%s',msg)
end
dbfData = cell(numel(records2read),numel(fields2read));
for k = 1:numel(fields2read),
n = fields2read(k);
fieldOffset = info.HeaderLength ...
+ sum([info.FieldInfo(1:(n-1)).Length]) ...
+ lengthOfDeletionIndicator;
fseek(dbfFileId,fieldOffset,'bof');
formatString = sprintf('%d*uint8=>char',info.FieldInfo(n).Length);
skip = info.RecordLength - info.FieldInfo(n).Length;
data = fread(dbfFileId,[info.FieldInfo(n).Length info.NumRecords],formatString,skip);
dbfData(:,k) = feval(info.FieldInfo(n).ConvFunc,(data(:,records2read)'));
end
fclose(dbfFileId);
function fields2read = matchFieldNames(info, requestedFieldNames)
allFieldNames = {info.FieldInfo.Name};
if isempty(requestedFieldNames)
if ~iscell(requestedFieldNames)
fields2read = 1:info.NumFields;
else
fields2read = [];
end
else
fields2read = [];
for k = 1:numel(requestedFieldNames)
index = strmatch(requestedFieldNames{k},allFieldNames,'exact');
if isempty(index)
wid = sprintf('MATLAB:%s:nonexistentDBFName',mfilename);
wrn = sprintf('DBF name ''%s'' %s\n%s',requestedFieldNames{k},...
'doesn''t match an existing DBF name.',...
' It will be ignored.');
warning(wid,wrn)
end
for l = 1:numel(index)
fields2read(end+1) = index(l);
end
end
end
function info = dbfinfo(fid)
[version, date, numRecords, headerLength, recordLength] = readFileInfo(fid);
fieldInfo = getFieldInfo(fid);
info.Filename = fopen(fid);
info.DBFVersion = version;
info.FileModDate = date;
info.NumRecords = numRecords;
info.NumFields = length(fieldInfo);
info.FieldInfo = fieldInfo;
info.HeaderLength = headerLength;
info.RecordLength = recordLength;
function [version, date, numRecords, headerLength, recordLength] = readFileInfo(fid)
fseek(fid,0,'bof');
version = fread(fid,1,'uint8');
year = fread(fid,1,'uint8') + 1900;
month = fread(fid,1,'uint8');
day = fread(fid,1,'uint8');
dateVector = datevec(sprintf('%d/%d/%d',month,day,year));
dateForm = 1;
date = datestr(dateVector,dateForm);
numRecords = fread(fid,1,'uint32');
headerLength = fread(fid,1,'uint16');
recordLength = fread(fid,1,'uint16');
function fieldInfo = getFieldInfo(fid)
lengthOfLeadingBlock = 32;
lengthOfDescriptorBlock = 32;
lengthOfTerminator = 1;
fieldNameOffset = 16;
fieldNameLength = 11;
fseek(fid,8,'bof');
headerLength = fread(fid,1,'uint16');
numFields = (headerLength - lengthOfLeadingBlock - lengthOfTerminator)...
/ lengthOfDescriptorBlock;
fseek(fid,lengthOfLeadingBlock + fieldNameOffset,'bof');
lengths = fread(fid,[1 numFields],'uint8',lengthOfDescriptorBlock - 1);
fseek(fid,lengthOfLeadingBlock,'bof');
data = fread(fid,[fieldNameLength numFields],...
sprintf('%d*uint8=>char',fieldNameLength),...
lengthOfDescriptorBlock - fieldNameLength);
data(data == 0) = ' ';
names = cellstr(data')';
fseek(fid,lengthOfLeadingBlock + fieldNameLength,'bof');
dbftypes = fread(fid,[numFields 1],'uint8=>char',lengthOfDescriptorBlock - 1);
typeConv = dbftype2matlab(upper(dbftypes));
fieldInfo = cell2struct(...
[names; {typeConv.MATLABType}; {typeConv.ConvFunc}; num2cell(lengths)],...
{'Name', 'Type', 'ConvFunc', 'Length'},1)';
function typeConv = dbftype2matlab(dbftypes)
typeLUT = ...
{'N', 'double', @str2double2cell;...
'F', 'double', @str2double2cell;...
'C', 'char', @cellstr;...
'D', 'char', @cellstr};
unsupported = struct('MATLABType', 'unsupported', ...
'ConvFunc', @cellstr);
numFields = length(dbftypes);
if numFields ~= 0
typeConv(numFields) = struct('MATLABType',[],'ConvFunc',[]);
end
for k = 1:numFields
idx = strmatch(dbftypes(k),typeLUT(:,1));
if ~isempty(idx)
typeConv(k).MATLABType = typeLUT{idx,2};
typeConv(k).ConvFunc = typeLUT{idx,3};
else
typeConv(k) = unsupported;
end
end
function out = str2double2cell(in)
if isempty(in)
out = {[NaN]};
return
end
fmt = sprintf('%%%df',size(in,2));
[data count] = sscanf(reshape(in',[1 numel(in)]),fmt);
if count == size(in,1)
out = cell(count,1);
for k = 1:count
out{k} = data(k);
end
else
out = num2cell(str2double(cellstr(in)));
end
更新
如果输入参数中数字的位数不同,STR2DOUBLE2CELL子函数有时会工作不正确(请参见此讨论)。
这是我的版本STR2DOUBLE2CELL:
function out = str2double2cell(in)
if isempty(in)
out = {[NaN]};
return
end
out = cellfun(@str2double,cellstr(in),'UniformOutput',false);