# coding=utf8
import struct
import datetime
import decimal
import itertools
import os
import itertools
from dbfpy import dbf
from dbfrw import *
class DbfLibrary():
def dbfreader(self, 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
# 读取文件的32个字符,前面4个x表示不需要,后面22x表示不需要,第4-7个字符为记录数,8-9为文件头长度
numrec, lenheader = struct.unpack('<xxxxLH22x', f.read(32))
numfields = int((lenheader - 32) / 32)
fields = []
for fieldno in xrange(numfields):
# 读取文件头中每个字段定义32个字符,把每一个字段里面的字段分解成字段名,数据类型,大小,精度
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] for field in fields]
yield [tuple(field[1:]) for field in fields]
# 如果包头有结束位,先读取
if lenheader % 32 == 1:
terminator = f.read(1)
# assert terminator == '\r'
fields.insert(0, ('DeletionFlag', 'C', 1, 0))
fmt = ''.join(['%ds' % fieldinfo[2] for fieldinfo in fields])
fmtsiz = struct.calcsize(fmt)
for i in xrange(numrec):
record = struct.unpack(fmt, f.read(fmtsiz))
if record[0] != ' ':
continue # deleted record
result = []
for (name, typ, size, deci), value in itertools.izip(fields, record):
if name == 'DeletionFlag':
continue
if typ == "N":
# print value
value = value.replace('\0', '').lstrip()
if value == '':
value = 0
elif deci:
value = value
else:
value = value
elif typ == 'D':
y, m, d = int(value[:4]), int(value[4:6]), int(value[6:8])
value = datetime.date(y, m, d)
elif typ == 'L':
value = (value in 'YyTt' and 'T') or (value in 'NnFf' and 'F') or '?'
elif typ == 'F':
value = float(value)
result.append(value)
yield result
yield lenheader
# result.append(lenheader)
# result = result.insert(len(result),str(lenheader))
# return
def DbfRead_Dic(self, filename):
'''
读取指定DBF库文件的所有数据,并以键值对方法存方数据\n
filename 为制定路径文件名 'C:/Users/Administrator/Desktop/dbpzhhzxx.dbf' \n
返回最后一行数据值 ['100888', '3 ', '100888 ', '0', '0689900052', 'D890792572', '20120521']
'''
f = open(filename, 'rb')
db = list(self.dbfreader(f))
cn = len(db)
f.close()
# 字段名,字段长度,记录数
fieldnames, fieldspecs, records = db[0], db[1], db[2:cn - 1]
lt=[]
if len(records)>0:
for i in records:
dic={}
for j in range (0,len(i)):
dic[fieldnames[j]]=i[j]
lt.append(dic)
return lt
def CreatDbfFile(self,filename, header, content=None,num=32):
# 打开dbf
db = dbf.Dbf(filename, new=True)
# 写列头
for field in header:
# 此处需要改成长度可配的,长度太短会导致数据被截断
if type(field) == unicode:
field = field.encode('GBK')
db.addField((field, 'C',num))
# 写数据
if content==None:
content=[[]]
elif type(content)==str:
content=eval(content)
sg=0
for i in content:#判断是否为双重列表
if i and type(i)==list:
sg=sg+1
if sg==len(content):
for record in content:
rec = db.newRecord()
for key, value in itertools.izip(header, record):
if type(value) == unicode:
rec[key] = value.encode('GBK')
else:
rec[key] = value
rec.store()
else:
rec = db.newRecord()
for key, value in itertools.izip(header, content):
if type(value) == unicode:
rec[key] = value.encode('GBK')
else:
rec[key] = value
rec.store()
# 关闭文档
db.close()
def DbfWrite_append(self, filename,content=None,num=32):
'''
功能描述:向指定dbf文件内容后追加数据
入参描述:
filename dbf文件路径和文件名
content 如果入参是content=["a","b"]就是在内容后最加一行数据
如果入参content=[["a","b"],[a,b,c],[d,d,f]],就是依次追加三行数据
num 设置单元格字符串最长限制
'''
if not os.path.exists(filename):
exit( u"输入路径或文件不存在!"+filename)
dbf = dbfrw()
f = open(filename, 'rb')
db = list(dbf.dbfreader(f))
cn = len(db)
f.close()
# 字段名,字段长度,记录数
header, fieldspecs, records = db[0], db[1], db[2:cn - 1]
if content == None:
content = [[]]
elif isinstance(content,str)==True:
content = eval(content)
if content==[]:
content = [[]]
sg =0
for i in content: # 判断是否为双重列表
if isinstance(i,list)==True :
sg =sg+1
if sg == len(content) and len(records)>0:
contents=records+content
self.CreatDbfFile(filename, header, contents,num)
elif len(records)>0:
records.append(content)
self.CreatDbfFile(filename,header,records,num)
else:
self.CreatDbfFile(filename, header, content,num)
# Example calls
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
if __name__ == '__main__':
a=DbfLibrary()
filename='C:\\Users\\Administrator\\Desktop\\dbpzhhzxx233.dbf'
filenamenew = 'C:\\Users\\Administrator\\Desktop\\dbpzhhzxx11.dbf'
b="['ZQZH','JGBM','ZHMC','ZJLB','ZJBH','ZHZT','LXFS','KHFXDJCPJG','JGBZ']"
c=['ZQZH','JGBM','ZHMC','ZJLB','ZJBH',0.444,'LXFS','KHFXDJCPJG',2]
a.DbfWrite_append(filename,c)
# a.CreatDbfFile(filenamenew,b,c)
# data = a.DbfRead_Dic(filename)
# print data
# b="['ZQZH','JGBM','ZHMC','ZJLB','ZJBH','ZHZT','LXFS','KHFXDJCPJG','JGBZ']"
# a.DbfLastWrite(filename,b)
#
# data=a.DbfRead_Dic(filename)
# for i in data:
# print i['ZHMC'].decode("GBK")
# '''