#!/usr/local/bin/python
#
'''\
load dbf file into memory as a DbfLoader object, read file specs and data
mocons.lib.persist.dbfload.py
jjk 11/05/97 001 from MdcDbf.py import
jjk 11/06/97 002
jjk 12/16/97 003 for CTdataTable ver 010
jjk 02/13/98 004 from CTdbfLoader import
jjk 11/15/99 005 documentation updates
Usage:
see doc string for DbfLoader class
also see demo1() function
*** !! USE AT YOUR OWN RISK !! ***
*** !! NO WARRANTIES WHATSOEVER !! ***
Jeff Kunce <kuncej@mail.conservation.state.mo.us>
'''
import sys
import string
try: import binnum
except ImportError: from mocons.lib.utils import binnum
class DbfLoader:
'''loads the contents of a dbf file into memory
After successful load, the following info is available:
self.fileName
self.version
self.lastUpdate ('mm/dd/yy')
self.recordCount
self.headerLength
self.recordLength
self.fieldDefs (list of DbfFieldDef objects)
self.fieldNames()
self.fieldInfo() (list of (name, type, length, decimalCount))
self.allRecords
self.recordStatus
self.fieldNames()
self.liveRecords()
self.deletedRecords()
jjk 02/13/98'''
def __init__(self, dbfFileName=''):
'''public: initialize the receiver
jjk 02/13/98'''
if (dbfFileName): self.loadDbfFileName(dbfFileName)
def loadDbfFileName(self, dbfFileName):
'''public: load the specified dbf file into the receiver
jjk 02/13/98'''
dbfs = open(dbfFileName, 'rb')
self.loadDbfFile(dbfs)
dbfs.close()
self.fileName = dbfFileName
def loadDbfFile(self, dbfFile):
'''public: load data from opendbffile import
jjk 02/13/98'''
self.fileName = ''
self.readHeaderData(dbfFile)
self.loadRecordData(dbfFile)
def readHeaderData(self, dbfs):
'''private: read and dcode dbf header data from binaryinputstream import
jjk 11/05/97'''
self.version = ord(dbfs.read(1))
year = ord(dbfs.read(1))
month = ord(dbfs.read(1))
day = ord(dbfs.read(1))
self.lastUpdate = "%2d/%2d/%2d" % (month, day, year)
self.recordCount = binnum.unsigned_from_Intel4(dbfs.read(4))
self.headerLength = binnum.unsigned_from_Intel2(dbfs.read(2))
self.recordLength = binnum.unsigned_from_Intel2(dbfs.read(2))
reserved = dbfs.read(20)
self.fieldDefs = []
fieldCount = (self.headerLength - 33) / 32
start = 1 #byte 0 is delete flag
for fn in range(fieldCount):
fd = DbfFieldDef()
fd.readFieldDef(dbfs, start)
self.fieldDefs.append(fd)
start = fd.end
skip = dbfs.read(1)
def loadRecordData(self, dbfs):
'''private: read and dcode dbf record data from binaryinputstream. import
load data into data table.
jjk 02/13/98'''
self.allRecords = []
self.recordStatus = []
for rn in range(self.recordCount):
rawrec = dbfs.read(self.recordLength)
record = []
for fd in self.fieldDefs:
record.append(fd.decodeValue(rawrec))
self.allRecords.append(record)
self.recordStatus.append(rawrec[0]==' ')
def fieldNames(self):
'''Public: answer a list of the receiver's field names.
jjk 11/06/97'''
return(map(lambda x: x.name, self.fieldDefs))
def fieldInfo(self):
'''Public: answer a list of the receiver's field info.
for each: (name, type, length, decimalCount)
jjk 11/06/97'''
fi = []
for fd in self.fieldDefs:
fi.append(fd.fieldInfo())
return(fi)
def liveRecords(self):
'''Public: answer a list undeleted records from thefile import
jjk 02/13/98'''
liveRecs = []
for rn in range(len(self.recordStatus)):
if (self.recordStatus[rn]):
liveRecs.append(self.allRecords[rn])
return(liveRecs)
def deletedRecords(self):
'''Public: answer a list deleted records from thefile import
jjk 02/13/98'''
delRecs = []
for rn in range(len(self.recordStatus)):
if (not self.recordStatus[rn]):
delRecs.append(self.allRecords[rn])
return(delRecs)
def reportOn(self, outs=sys.stdout):
'''Public: report info about the receiver
jjk 02/13/98'''
outs.write('DbfLoader file: %s\n'%self.fileName)
outs.write(' version: %d last update: %s\n'%(self.version,self.lastUpdate))
outs.write(' hdrlen: %d reclen: %d reccnt: %d\n'%(self.headerLength,self.recordLength,self.recordCount))
outs.write(' FIELDS:\n')
for fi in self.fieldInfo():
outs.write(' %12s %2s %4d %4d\n'%fi)
outs.write(' deleted records: %d\n\n'%len(self.deletedRecords()))
class DbfFieldDef:
def readFieldDef(self, dbfs, start):
'''read and dcode dbf field definition from binaryinputstream import
jjk 11/05/97'''
self.name = dbfs.read(11)
while (self.name[-1:] == '\000'): self.name = self.name[:-1]
self.type = dbfs.read(1)
dataAddress = binnum.unsigned_from_Intel4(dbfs.read(4))
self.length = ord(dbfs.read(1))
self.start = start
self.end = start + self.length
self.decimalCount = ord(dbfs.read(1))
reserved = dbfs.read(14)
def fieldInfo(self):
'''answer basic info about the receiver
jjk 02/13/98'''
return((self.name, self.type, self.length, self.decimalCount))
def decodeValue(self, rawrec):
'''decode and answer a field value from rawrec import
jjk 11/05/97'''
rawval = rawrec[self.start:self.end]
if (self.type == 'C'): #string
while (rawval[-1:] == ' '): rawval = rawval[:-1]
return rawval
if (self.type == 'D'): #date 'yyyymmdd'
return rawval
if (self.type == 'N'): #numeric
if (self.decimalCount == 0):
rawval = string.strip(rawval)
if (rawval==''): return(0)
try:
return(string.atoi(rawval))
except ValueError:
return(string.atol(rawval))
rv1 = string.strip(rawval[:-self.decimalCount])
rv2 = rawval[:-self.decimalCount]
rawval = rv1+'.'+rv2
if (rawval=='.'): return(0.0)
return string.atof(rawval)
return(rawval)
def demo1():
dl1 = DbfLoader('county.dbf')
dl1.reportOn()
print 'sample records:'
for i1 in range(min(3,dl1.recordCount)):
print dl1.allRecords[i1]
if (__name__=='__main__'):
import pdb
demo1()
|