/
MadDAD
/
alterplast
Обзор
Документация
Войти
/
MadDAD
/
alterplast
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
1cpp/Testing/Scripts/dbfpy/dbf.py
649 строк
19 KB
trdm
24 мар 2017, 11:45
24 мар 2017, 11:45
3b762c0
Код
Авторство
О чём код?
#!/usr/local/bin/python # '''\ access a dbf file (read access works, write *might* work) mocons.persist.dbf.py jjk 02/18/98 001 from dbfload.py 004 jjk 02/19/98 002 add create/write capabilities jjk 02/20/98 003 fix problems, add more features jjk 06/08/98 004 fix problems, add more features jjk 08/24/98 005 add some encodeValue methods (not tested), other tweaks jjk 11/15/99 006 documentation updates, add demo Example Usage: aDbf = Dbf() aDbf.openFile('fname.dbf', readOnly=1) numberOfRecords = len(aDbf) aDbfRecord = aDbf[recordIndex] aFieldName = aDbf.fieldNames[fieldIndex] aFieldValue = aDbfRecord[aFieldName] also see demo1() function *** !! USE AT YOUR OWN RISK !! *** *** !! NO WARRANTIES WHATSOEVER !! *** Jeff Kunce <kuncej@mail.conservation.state.mo.us> ''' import sys import string import time try: import binnum except ImportError: from mocons.lib.utils import binnum try: import strutil except ImportError: from mocons.lib.utils import strutil class Dbf: '''access dBase (.dbf) data jjk 02/18/98''' def __init__(self): '''public: initialize the receiver jjk 02/18/98''' self._reset() def _reset(self): '''private: reset the receiver instance variables to the initial state jjk 02/18/98''' self.dbfName = '' # dbf file name '' if none self.dbfStream = None # file object open on dbf data self.changed = 0 def close(self): '''public: flush data, close files, clear buffers jjk 02/18/98''' self.flush() if (self.isOpen()): self.dbfStream.close() self._reset() def isOpen(self): '''public: answer true if the receiver has an open file jjk 02/18/98''' return(self.dbfStream!=None) def recordCount(self): '''public: answer the number of records in the receiver jjk 02/18/98''' return(self.header.recordCount) def fieldNames(self): '''public: answer the names of the receivers fields jjk 02/18/98''' return(self.header.fieldNames) def fieldDefinitions(self): '''public: answer the field definitions for the receiver jjk 02/19/98''' return(self.header.fieldDefs) def indexOfFieldName(self, fieldName): '''system: answer the index of fieldName in records of the receiver jjk 02/13/98''' return(self.header.fieldIndex[fieldName]) def flush(self): '''public: flush any data in memory to file jjk 02/19/98''' if (not self.isOpen()): return if (self.changed): self.header.setCurrentDate() self.header.writeOn(self.dbfStream) self.changed = 0 self.dbfStream.flush() def openFile(self, dbfFileName, readOnly=0): '''public: open the receiver on the specified dbf file name jjk 08/24/98''' if (readOnly): mode = 'rb' else: mode = 'r+b' dbfs = open(dbfFileName, mode) self.openOn(dbfs) self.dbfName = dbfFileName return(self) def openOn(self, dbfFileStream): '''public: open the receiver on the open dbf file stream jjk 08/24/98''' self.close() self.header = DbfHeader() self.header.readFrom(dbfFileStream) self.dbfStream = dbfFileStream return(self) def openString(self, aString): '''public: open the receiver on a string of raw dbf data jjk 08/24/98''' import StringIO dbfs = StringIO.StringIO(aString) self.openOn(dbfs) self.dbfName = '' return(self) def rawContents(self): '''public: answer the complete raw contents of the receiver as a string jjk 02/20/98''' self.dbfStream.seek(0) return(self.dbfStream.read()) def reportOn(self, outs=sys.stdout, indent=0): '''Public: report info about the receiver jjk 02/18/98''' inds = indent*'\t' outs.write('%sDbf Instance file: %s\n'%(inds,self.dbfName)) self.header.reportOn(outs, indent+1) #outs.write(' deleted records: %d\n\n'%len(self.deletedRecords())) def __len__(self): '''public: answer number of records in the receiver jjk 06/08/98''' return(self.recordCount()) def __getitem__(self, anIndex): '''public: answer the DbfRecordread at anIndex in the receiver. jjk 02/18/98''' rec = DbfRecord(self) rec.readData(anIndex) return(rec) def newRecord(self): '''public: answer new DbfRecordread created for the receiver. jjk 02/19/98''' rec = DbfRecord(self) return(rec) def append(self, aDbfRecord): '''public: add aDbfRecord to the end of the receiver jjk 02/19/98''' aDbfRecord.recordIndex = self.header.recordCount aDbfRecord.writeData() self.header.recordCount = self.header.recordCount + 1 self.changed = 1 def __setitem__(self, anIndex, aDbfRecord): '''public: write DbfRecordread at anIndex in the receiver. jjk 02/19/98''' aDbfRecord.writeData() self.changed = 1 class DbfHeader: '''system: header data for a dbf file jjk 02/18/98''' def __init__(self): '''public: initialize the receiver jjk 02/18/98''' self._reset() def _reset(self): '''system: reset the receiver data jjk 02/18/98''' self.version = 0x03 #0x03=no memo 0x83=memo self.setCurrentDate() self.recordCount = 0 self._computeHeaderLength() self.recordLength = 0 self.fieldDefs = [] self.fieldNames = [] self.fieldIndex = {} def setCurrentDate(self): '''system: set the receiver's date values to current day jjk 02/18/98''' timeA = time.localtime(time.time()) self.year = timeA[0] self.month = timeA[1] self.day = timeA[2] def _computeHeaderLength(self): '''private: compute the receiver's headerLength value jjk 02/18/98''' self.headerLength = 32+(32*self.recordCount)+1 def addFieldDef(self, aFieldDef): '''system: read and dcode dbf header data from binary input stream jjk 02/18/98''' self.fieldDefs.append(aFieldDef) self.fieldNames.append(aFieldDef.name) self.fieldIndex[aFieldDef.name] = len(self.fieldNames)-1 def readFrom(self, dbfs): '''system: read and decode dbf header data from binary input stream jjk 02/19/98''' self._reset() dbfs.seek(0) hdrRawData = dbfs.read(32) self._fromRawData(hdrRawData) fieldCount = (self.headerLength - 33) / 32 startPos = 1 #byte 0 is delete flag for fn in range(fieldCount): rawFieldDef = dbfs.read(32) fd = DbfFieldDefFromRawData(rawFieldDef, startPos) self.addFieldDef(fd) startPos = fd.end skip = dbfs.read(1) def _fromRawData(self, rawData): '''private: instantiate the receiver from dbf 32-byte raw header jjk 02/19/98''' self.version = ord(rawData[0]) self.year = 1900+ord(rawData[1]) self.month = ord(rawData[2]) self.day = ord(rawData[3]) self.recordCount = binnum.unsigned_from_Intel4(rawData[4:8]) self.headerLength = binnum.unsigned_from_Intel2(rawData[8:10]) self.recordLength = binnum.unsigned_from_Intel2(rawData[10:12]) #reserved = rawData[12:32] def writeOn(self, dbfs): '''system: encode and write dbf header data on binary output stream jjk 02/19/98''' dbfs.seek(0) dbfs.write(self._asRawData()) for fd in self.fieldDefs: dbfs.write(fd.asRawData()) dbfs.write(chr(0x0D)) # cr at end of all hdr data def _asRawData(self): '''private: encode and answer dbf 32-byte raw header from receiver jjk 02/19/98''' rdl = [chr(self.version), chr(self.year-1900), chr(self.month), chr(self.day), binnum.unsigned_as_Intel4(self.recordCount), binnum.unsigned_as_Intel2(self.headerLength), binnum.unsigned_as_Intel2(self.recordLength), 20*chr(0)] return(string.joinfields(rdl,'')) def reportOn(self, outs=sys.stdout, indent=0): '''Public: report info about the receiver jjk 02/18/98''' inds = indent*'\t' outs.write('%sversion: 0x%x last update: %d/%d/%d\n'%(inds, self.version, self.year,self.month,self.day)) outs.write('%shdrlen: %d reclen: %d reccnt: %d\n'%(inds, self.headerLength, self.recordLength,self.recordCount)) outs.write(inds+' Field Name Type Len Dec\n') for fdef in self.fieldDefs: fdef.reportOn(outs, indent) def DbfFieldDefFromRawData(rawFieldDef, startPos): '''system: answer an appropriate DbfFieldDef decoded from the raw definition jjk 02/18/98''' fType = rawFieldDef[11] if (fType=='C'): fd = DbfCharacterFieldDef() elif (fType=='N'): fd = DbfNumericFieldDef() elif (fType=='L'): fd = DbfLogicalFieldDef() elif (fType=='M'): fd = DbfMemoFieldDef() elif (fType=='D'): fd = DbfDateFieldDef() else: raise ValueError, 'Unknown Field Type: '+fType fd.fromRawData(rawFieldDef, startPos) return(fd) class DbfFieldDef: '''superclass for field definition classes jjk 02/18/98''' def __init__(self): '''public: initialize the receiver jjk 02/18/98''' self._reset() def _reset(self): '''system: reset the receiver data jjk 02/18/98''' self.name = '' dataAddress = 0 self.length = 0 self.decimalCount = 0 self.start = 0 self.end = 0 def fromRawData(self, rawFieldDef, startPos): '''system: decode dbf field definition from 32-byte raw dbf data jjk 02/18/98''' self.name = strutil.unzfill(rawFieldDef[:11]) dataAddress = binnum.unsigned_from_Intel4(rawFieldDef[12:16]) self.length = ord(rawFieldDef[16]) self.start = startPos self.end = startPos + self.length self.decimalCount = ord(rawFieldDef[17]) def asRawData(self): '''system: encode and answer decode dbf field definition as 32-byte raw dbf data jjk 02/19/98''' rdl = [strutil.padTrailing(self.name, 11, chr(0)), self.typeCode(), binnum.unsigned_as_Intel4(0), #data address chr(self.length), chr(self.decimalCount), 14*chr(0)] return(string.joinfields(rdl,'')) def reportOn(self, outs=sys.stdout, indent=0): '''Public: report info about the receiver jjk 02/18/98''' outs.write(indent*'\t') outs.write('%11s %1s %3d %3d\n'%self.fieldInfo()) def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' raise NameError, 'typeCode() must be implemented by subclass' def fieldInfo(self): '''Public: answer tuple of basic info about the receiver jjk 02/18/98''' return((self.name, self.typeCode(), self.length, self.decimalCount)) def decodeFromRecord(self, rawrec): '''system: decode and answer the field value from rawrec jjk 02/20/98''' rawval = rawrec[self.start:self.end] return(self.decodeValue(rawval)) def decodeValue(self, rawval): '''system: answer field value decoded from raw value string jjk 02/20/98''' raise NameError, 'decodeValue() must be implemented by subclass' def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 02/19/98''' raise NameError, 'encodeValue() must be implemented by subclass' def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' raise NameError, 'defaultValue() must be implemented by subclass' class DbfCharacterFieldDef(DbfFieldDef): def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' return('C') def decodeValue(self, rawval): '''system: decode and answer the field value from rawrec jjk 02/18/98''' return(strutil.stripTrailing(rawval, ' ')) def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' return('') def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 02/19/98''' rv = str(fieldValue)[:self.length] return(strutil.padTrailing(rv, self.length)) class DbfNumericFieldDef(DbfFieldDef): def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' return('N') def decodeValue(self, rawval): '''system: decode and answer the field value from rawrec jjk 06/08/98''' if (self.decimalCount == 0): rawval = string.strip(rawval) if (rawval==''): return(0) ''' patch from Steve Jibson <stevej@arcos.parlant.com> ''' try: return(string.atoi(rawval)) except ValueError: return(string.atol(rawval)) if (string.find(rawval, '.')<0): rv1 = rawval[:-self.decimalCount] rv2 = rawval[-self.decimalCount:] rawval = string.strip(rv1+'.'+rv2) if (rawval=='.'): return(0.0) return string.atof(rawval) def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' return(0) def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 08/24/98''' fl = self.length # excel and arcview say, there is a point! (fiby) #if (self.decimalCount>0): # fl = fl + 1 fmt = '%%%d.%df'%(fl,self.decimalCount) rv = fmt%fieldValue # excel and arcview say, there is a point! (fiby) #if (self.decimalCount>0): # p1 = self.length-self.decimalCount # rv = rv[:p1] + "." + rv[p1+1:] return(rv) class DbfLogicalFieldDef(DbfFieldDef): def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' return('L') def decodeValue(self, rawval): '''system: decode and answer the field value from rawrec (1 for true, 0 for false, -1 for dont know) jjk 02/18/98''' if (rawval=='?'): return(-1) if (rawval in 'YyTt'): return(1) if (rawval in 'NnFf'): return(0) raise ValueError, 'invalid logical value: '+rawval def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' return(-1) def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 08/24/98''' if (fieldValue==-1): return('?') if (fieldValue==1): return('T') else: return('F') class DbfMemoFieldDef(DbfFieldDef): def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' return('M') def decodeValue(self, rawval): '''system: answer .dbt block number jjk 02/18/98''' try: return(string.atoi(string.strip(rawval))) except ValueError: return(string.atol(string.strip(rawval))) def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' return(0) def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 02/19/98''' rv = str(fieldValue)[:self.length] return(strutil.padTrailing(rv, self.length)) class DbfDateFieldDef(DbfFieldDef): def typeCode(self): '''Public: answer one-character type code of the receiver jjk 02/18/98''' return('D') def decodeValue(self, rawval): '''system: answer (year, month, day) tuple jjk 06/08/98''' try: year = string.atoi(rawval[:4]) except ValueError: year = 0 try: month = string.atoi(rawval[4:6]) except ValueError: month = 0 try: day = string.atoi(rawval[6:]) except ValueError: day = 0 return((year,month,day)) def defaultValue(self): '''Public: answer the default value for fields defined by the receiver jjk 02/19/98''' timeA = time.localtime(time.time()) year = timeA[0] month = timeA[1] day = timeA[2] return((year,month,day)) def encodeValue(self, fieldValue): '''system: answer raw data string encoded from a field value jjk 08/24/98''' if (fieldValue[0] == 0) and (fieldValue[1] == 0) and (fieldValue[2] == 0): return '\x20' * 8 year = fieldValue[0] if (year < 50): year = year + 2000 if (year < 100): year = year + 1900 ys = str(year) if fieldValue[0] == 0: ys = ' ' ms = ('00'+str(fieldValue[1]))[-2:] if fieldValue[1] == 0: ms = ' ' ds = ('00'+str(fieldValue[2]))[-2:] if fieldValue[2] == 0: ds = ' ' return(ys+ms+ds) class DbfRecord: '''system: a Dbf file record jjk 02/18/98''' def __init__(self, aDbf): '''public: initialize the receiver jjk 02/19/98''' self.dbf = aDbf self._reset() def _reset(self): '''private: reset the receiver data jjk 02/19/98''' self.recordIndex = -1 self.isDeleted = 0 self.fieldData = [] for fd in self.dbf.header.fieldDefs: self.fieldData.append(fd.defaultValue()) def store(self): '''public: [re]store the receiver in its dbf jjk 02/19/98''' if (self.recordIndex<0): self.dbf.append(self) else: self.dbf[self.recordIndex] = self def writeData(self): '''system: write the receiver data to its recordIndex jjk 02/19/98''' if (self.recordIndex<0): raise IndexError, 'Dbf record numbers must be >=0' len = self.dbf.header.recordLength pos = self.dbf.header.headerLength+(self.recordIndex*len) rawData = self.asRawData() self.dbf.dbfStream.seek(pos) self.dbf.dbfStream.write(rawData) def readData(self, recordIndex): '''system: read the receiver data from the specified index jjk 02/19/98''' if (recordIndex<0): raise IndexError, 'Dbf record numbers must be >=0' if (recordIndex>=self.dbf.header.recordCount): raise IndexError, 'Only '+str(self.dbf.header.recordCount)+' records in Dbf' len = self.dbf.header.recordLength pos = self.dbf.header.headerLength+(recordIndex*len) self.dbf.dbfStream.seek(pos) rawData = self.dbf.dbfStream.read(len) self.fromRawData(rawData) self.recordIndex = recordIndex def fromRawData(self, rawDataString): '''system: instantiate the receiver from a raw data string jjk 02/19/98''' self._reset() self.isDeleted = (rawDataString[0]==chr(0x2A)) #del='*' notDel=' ' for fieldIx in range(len(self.fieldData)): fd = self.dbf.header.fieldDefs[fieldIx] self.fieldData[fieldIx] = fd.decodeFromRecord(rawDataString) def asRawData(self): '''system: answer a raw dbf string generated from the receiver jjk 02/19/98''' rawFields = [] if (self.isDeleted): rawFields.append(chr(0x2A)) # '*' else: rawFields.append(chr(0x20)) # ' ' for fieldIx in range(len(self.fieldData)): fdef = self.dbf.header.fieldDefs[fieldIx] fdat = fdef.encodeValue(self.fieldData[fieldIx]) rawFields.append(fdat) return(string.joinfields(rawFields,'')) def asList(self): '''Public: answer a list of receiver's fields jjk 02/18/98''' return(self.fieldData) def asDict(self): '''Public: answer a dictionary of receiver's fields jjk 02/19/98''' dict = {} for fldName in self.dbf.fieldNames(): dict[fldName] = self[fldName] return(dict) def __getitem__(self, fieldName): '''public: answer the value for specified field in the receiver jjk 02/13/98''' fldIx = self.dbf.indexOfFieldName(fieldName) return(self.fieldData[fldIx]) def __setitem__(self, fieldName, fieldValue): '''public: set the value for specified field in the receiver jjk 02/13/98''' fldIx = self.dbf.indexOfFieldName(fieldName) self.fieldData[fldIx] = fieldValue def demo1(): dbf1 = Dbf() dbf1.openFile('county.dbf', readOnly=1) dbf1.reportOn() print 'sample records:' for i1 in range(min(3,len(dbf1))): rec = dbf1[i1] for fldName in dbf1.fieldNames(): print '%s:\t %s'%(fldName, rec[fldName]) print dbf1.close() if (__name__=='__main__'): import pdb demo1()