Return a string suitable for writing directly to a binary dbf file. File f should be open for writing in a binary mode. Fieldnames should be no longer than ten characters and not include \x00. Fieldspecs are in the form (type, size, deci) where type is one of: C fo
(f, fieldnames, fieldspecs, records)
| 59 | |
| 60 | |
| 61 | def dbfwriter(f, fieldnames, fieldspecs, records): |
| 62 | """ Return a string suitable for writing directly to a binary dbf file. |
| 63 | |
| 64 | File f should be open for writing in a binary mode. |
| 65 | |
| 66 | Fieldnames should be no longer than ten characters and not include \x00. |
| 67 | Fieldspecs are in the form (type, size, deci) where |
| 68 | type is one of: |
| 69 | C for ascii character data |
| 70 | M for ascii character memo data (real memo fields not supported) |
| 71 | D for datetime objects |
| 72 | N for ints or decimal objects |
| 73 | L for logical values 'T', 'F', or '?' |
| 74 | size is the field width |
| 75 | deci is the number of decimal places in the provided decimal object |
| 76 | Records can be an iterable over the records (sequences of field values). |
| 77 | |
| 78 | """ |
| 79 | # header info |
| 80 | ver = 3 |
| 81 | now = datetime.datetime.now() |
| 82 | yr, mon, day = now.year-1900, now.month, now.day |
| 83 | numrec = len(records) |
| 84 | numfields = len(fieldspecs) |
| 85 | lenheader = numfields * 32 + 33 |
| 86 | lenrecord = sum(field[1] for field in fieldspecs) + 1 |
| 87 | hdr = struct.pack('<BBBBLHH20x', ver, yr, mon, day, numrec, lenheader, lenrecord) |
| 88 | f.write(hdr) |
| 89 | |
| 90 | # field specs |
| 91 | for name, (typ, size, deci) in itertools.izip(fieldnames, fieldspecs): |
| 92 | name = name.ljust(11, '\x00') |
| 93 | fld = struct.pack('<11sc4xBB14x', name, typ, size, deci) |
| 94 | f.write(fld) |
| 95 | |
| 96 | # terminator |
| 97 | f.write('\r') |
| 98 | |
| 99 | # records |
| 100 | for record in records: |
| 101 | f.write(' ') # deletion flag |
| 102 | for (typ, size, deci), value in itertools.izip(fieldspecs, record): |
| 103 | if typ == "N": |
| 104 | value = str(value).rjust(size, ' ') |
| 105 | elif typ == 'D': |
| 106 | value = value.strftime('%Y%m%d') |
| 107 | elif typ == 'L': |
| 108 | value = str(value)[0].upper() |
| 109 | else: |
| 110 | value = str(value)[:size].ljust(size, ' ') |
| 111 | assert len(value) == size |
| 112 | f.write(value) |
| 113 | |
| 114 | # End of file |
| 115 | f.write('\x1A') |
| 116 | |
| 117 | |
| 118 | # ------------------------------------------------------- |
no test coverage detected