1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """
16 This is a module for reading dbf files.
17
18 It has been modified thanks to suggestions and patches from Jeff Bauer
19 and Kevin Dahlhausen. Unfortunately I lost patches which fix
20 endianness problems, which were sent to me by someone, so that will
21 have to wait. I do not use this module much these days, but since it
22 seems to be in use "out there" I thought I would finally make an
23 update available. This version should be more portable. Also, rather
24 than printing an error message an exception is now raised when the dbf
25 file appears to be corrupt.
26
27 Usage: the following
28
29 import dbf
30 db = dbf.dbf('mydata.dbf')
31
32 creates a dbf object db associated with an existing dbf file
33 'mydata.dbf'. The dbf file is opened by the constructor. If the file
34 is not there IOError is raised. If the file appears not to be a dbf
35 format file, TypeError is raised.
36
37 If you prefer to create a dbf object, but open the actual file later,
38 you can use the following:
39
40 import dbf
41 db = dbf.dbf('mydata.dbf', openit=0)
42
43 and then you can call
44
45 db.open()
46
47 to actually open the file. Note that the constructor, if called this
48 way, does not verify that the file is there, so the IOError exception
49 is raised by the call to open.
50
51 Once the dbf object is created and opened (implicitly or not), the
52 following are available:
53
54 -- db.fields : returns a a list of tuples describing the fields
55 -- db.nrecs : returns the number of records
56 -- db[n] : returns a tuple containing record number n (0 <= n < nrecs)
57 -- db.status(): prints some essential data about the dbf file
58
59 So to list the first two fields of mydata.dbf, assuming they are string
60 fields, one might write:
61
62 import dbf
63 from string import strip
64 db=dbf.dbf('mydata.dbf')
65 for k in db:
66 print "%s, %s" % (strip(k[1]), strip(k[2]))
67
68
69 Good luck!
70
71 """
72
73
74 from struct import unpack
75
78 self.fname = fname
79 if openit:
80 self.open()
81
83 self.f = open(self.fname,'rb')
84 head = self.f.read(32)
85 if (head[0] != '\003') and (head[0] != '\203') and (head[0] != '\365'):
86 raise TypeError, 'Not a Dbase III+ file!'
87 (self.nrecs, self.hlen, self.rlen) = unpack('4xihh20x', head)
88 fdalen = (self.hlen - 33)/32
89
90 fda = []
91 for k in range(fdalen):
92 fda.append(self.f.read(32))
93
94 self.fields = []
95
96 self.fieldindex = {}
97 idx = 0
98 for fd in fda:
99 bytes = unpack('12c4xBb14x', fd)
100 field = ""
101 for i in range(11):
102 if bytes[i] == '\000':
103 break
104 field = field+bytes[i]
105 type = bytes[11]
106 length = bytes[12]
107 dec = bytes[13]
108 self.fields.append((field,type,length,dec))
109 self.fieldindex[idx]=field
110 idx=idx+1
111
112
113 - def _get(self, recno):
114 offs = self.hlen + recno*self.rlen
115 self.f.seek(offs,0)
116 return self.f.read(self.rlen)
117
119 if recno < 0 or recno >= self.nrecs:
120 raise IndexError
121 else:
122 raw = self._get(recno)
123 res = []
124 pos = 0
125 for field in self.fields:
126 end = pos+field[2]
127 item = raw[pos+1:end+1]
128 pos=end
129 res.append(item)
130 return tuple(res)
131
133 res = self.__getitem__(recno)
134 d = {}
135 i = 0
136 for field in res:
137 d[self.fieldindex[i]]=field
138 i = i+1
139 return d
140
141
142
143
145 print ''
146 print 'Header length :', self.hlen
147 print 'Record length :', self.rlen
148 print 'Number of records :', self.nrecs
149 print ''
150 print '%-12s %-12s %-12s %-12s' % ('Field','Type','Length','Decimal')
151 print '%-12s %-12s %-12s %-12s' % ('-----','----','------','-------')
152 for k in self.fields:
153 print '%-12s %-12s %-12s %-12s' % k
154 print ''
155
158
159
160
161
162
163
164
165