使用dbf包编辑.dbf文件时出现BadDataError

时间:2017-02-09 16:18:30

标签: python-2.7 dbf dbase

我最近在unix系统上从大气模型(HYSPLIT)生成了数千个shapefile输出和附带的.dbf文件。转换器txt2dbf用于将shapefile属性表(文本文件)转换为.dbf。

不幸的是,出现了错误(可能是分隔符/字段长度错误),因为输出.dbf文件存在2个问题,如下所示:

  1. dbf的某些字段包含不应存在的数据。这些数据溢出"溢出"来自邻近的田野。
  2. 添加了一个不应该存在的附加字段(它实际上来自文本文件的第一个记录的一部分," 1000 201")。
  3. 这是输出dbf中第一条记录的示例(使用dbview unix包检索):

      

    Trajnum:1001 2
      Yyyymmdd:0111231 2
      时间:300
      等级:0      1000 201:

    这就是我的预期:

      Trajnum:1000
      Yyyymmdd:20111231
      时间:2300
      等级:0。

    另外,我正在考虑如何防止这种情况再次发生,但理想情况下,我希望能够修复现有的.dbf文件。不幸的是,每个模型运行都删除了文本文件,因此"修复" .dbf文件是唯一的选择。

    我解决上述问题的方法是:

    1. 使用dbf.add_fieldsdbf.write(python包dbf)从新变量中存在的字段中提取信息,然后使用dbf.delete_fields删除旧的错误字段。
    2. 删除不需要的附加字段。
    3. 这是我尝试过的:

              with dbf.Table(db) as db:
                  db.add_fields("TRAJNUMc C(4)") #create new fields
                  db.add_fields("YYYYMMDDc C(8)")
                  db.add_fields("TIMEc C(4)")
                  for record in db: #extract data from fields
                          dbf.write(TRAJNUMc=int(str(record.Trajnum)[:4]))
                          dbf.write(YYYYMMDDc=int(str(record.Trajnum)[-1:] + str(record.Yyyymmdd)[:7]))
                          dbf.write(TIMEc=record.Yyyymmdd[-1:] + record.Time[:])
                  db.delete_fields('Trajnum') # delete the incorrect fields
                  db.delete_fields('Yyyymmdd')
                  db.delete_fields('Time')
                  db.delete_fields('1000 201') #delete the unwanted field
                  db.pack()
      

      但这会产生以下错误:

      dbf.ver_2.BadDataError: record data is not the correct length (should be 31, not 30)
      

      鉴于txt2dbf转换存在明显问题,我在记录数据长度中发现错误并不奇怪。但是,这是否意味着该文件已完全损坏,并且我无法提取所需的信息(令人沮丧,因为我可以看到它存在)?

      编辑:

      而不是试图编辑“坏”' .dbf文件,似乎是一种更好的方法1.从坏文件中提取所需数据到文本然后2.写入新的dbf。 (参见Ethan Furman的评论/答案)。

      编辑:

      我需要修复/恢复数据的错误.dbf文件的示例可以在这里找到:

      https://www.dropbox.com/s/9y92f7m88a8g5y4/p0001120110.dbf?dl=0

      可以在此处找到创建错误dbf文件的示例.txt文件:

      https://www.dropbox.com/s/d0f2c0zehsyy8ab/attTEST.txt?dl=0

1 个答案:

答案 0 :(得分:0)

要修复数据并重新创建原始文本文件,此代码段应该有所帮助:

import dbf

table = dbf.Table('/path/to/scramble/table.dbf')
with table:
    fixed_data = []
    for record in table:
        # convert to str/bytes while skipping delete flag
        data = record._data[1:].tostring()
        trajnum = data[:4]
        ymd = data[4:12]
        time = data [12:16]
        level = data[16:].strip()
        fixed_data.extend([trajnum, ymd, time, level])

new_file = open('repaired_data.txt', 'w')
for line in fixed_data:
    new_file.write(','.join(line) + '\n')

假设您的所有数据文件看起来都像您的样本(大的 IF 是数据没有嵌入的逗号),那么这个粗略的代码应该有助于将您的文本文件转换为dbfs:

raw_data = open('some_text_file.txt').read().split('\n')
final_table = dbf.Table(
        'dest_table.dbf',
        'trajnum C(4); yyyymmdd C(8); time C(4); level C(9)',
        )
with final_table:
    for line in raw_data:
        fields = line.split(',')
        final_table.append(tuple(fields))

# table has been populated and closed

当然,如果你想:

,你可以获得更好的并使用实际日期和数字字段
# dbf string becomes
'trajnum N; yyyymmdd D; time C(4), level N'

#appending data loop becomes
    for line in raw_data:
        trajnum, ymd, time, level = line.split(',')
        trajnum = int(trajnum)
        ymd = dbf.Date(ymd[:4], ymd[4:6], ymd[6:])
        level = int(level)
        final_table.append((trajnum, ymd, time, level))
相关问题