importstruct,datetime,decimal,itertools
defdbfreader(f):
"""Returns an iterator over records in a Xbase DBF file.
The first row returned contains the field names.
The second row contains field specs: (type, size, decimal places).
Subsequent rows contain the data records.
If a record is marked as deleted, it is skipped.
File should be opened for binary reads.
"""
# See DBF format spec at:
# http://www.pgts.com.au/download/public/xbase.htm#DBF_STRUCT
numrec,lenheader=struct.unpack('
numfields=(lenheader-33)// 32
fields=[]
forfieldnoinxrange(numfields):
name,typ,size,deci=struct.unpack('<11sc4xBB14x',f.read(32))
name=name.replace('\0','')# eliminate NULs from string
fields.append((name,typ,size,deci))
yield[field[0]forfieldinfields]
yield[tuple(field[1:])forfieldinfields]
terminator=f.read(1)
assertterminator=='\r'
fields.insert(0,('DeletionFlag','C',1,0))
fmt=''.join(['%ds'%fieldinfo[2]forfieldinfoinfields])
fmtsiz=struct.calcsize(fmt)
foriinxrange(numrec):
record=struct.unpack(fmt,f.read(fmtsiz))
ifrecord[0]!=' ':
continue# deleted record
result=[]
for(name,typ,size,deci),valueinitertools.izip(fields,record):
ifname=='DeletionFlag':
continue
iftyp=="N":
value=value.replace('\0','').lstrip()
ifvalue=='':
value=0
elifdeci:
value=decimal.Decimal(value)
else:
value=int(value)
eliftyp=='D':
y,m,d=int(value[:4]),int(value[4:6]),int(val