Python 2.7 使用dbf包编辑.dbf文件时发生BadDataError

Python 2.7 使用dbf包编辑.dbf文件时发生BadDataError,python-2.7,dbf,dbase,Python 2.7,Dbf,Dbase,我最近在unix系统上从大气模型(HYSPLIT)生成了数千个shapefile输出和附带的.dbf文件。转换器txt2dbf用于将shapefile属性表(文本文件)转换为.dbf 不幸的是,出现了一些错误(可能是分隔符/字段长度错误),因为输出.dbf文件有两个问题,如下所示: dbf的某些字段包含不应该存在的数据。这些数据已从邻近油田“溢出” 添加了一个不应该存在的附加字段(它实际上来自文本文件第一条记录的一部分,“1000 201”) 这是输出dbf中第一条记录的示例(使用dbviewu

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

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

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

    Trajnum:10012
    Yyyymmdd:0111231 2
    时间:300
    级别:0。
    1000 201:

    以下是我所期望的:

    Trajnum:1000
    Yyyymmdd:20111231
    时间:2300
    级别:0

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

    我处理上述问题的方法是:

  • 使用
    dbf将确实存在的字段中的信息提取到新变量中。添加字段
    dbf。写入
    (python包
    dbf
    ),然后使用
    dbf删除旧的不正确字段。删除字段
  • 删除不需要的附加字段
  • 这就是我尝试过的:

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


    编辑: 与其试图编辑“bad”.dbf文件,不如使用1。将所需数据从坏文件中提取为文本,然后2。写入一个新的dbf。(见下面Ethan Furman的评论/回答)


    编辑: 我需要修复/恢复数据的错误.dbf文件示例如下:

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


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

    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')
    
    假设您的所有数据文件看起来都像您的示例(如果数据没有嵌入逗号,则为big),那么此粗略代码将有助于将文本文件转换为DBF:

    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))
    

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

    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')
    
    假设您的所有数据文件看起来都像您的示例(如果数据没有嵌入逗号,则为big),那么此粗略代码将有助于将文本文件转换为DBF:

    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))
    

    看起来从dbf文件重建文本文件然后再重新转换可能更容易——你试过了吗?谢谢,Ethan。不,我没想到要试试这个。。看起来可能是一张越狱卡。。这是不是将我使用的
    txt2dbf-C7-C9-C5-C9-d,-d,-d,file.att file.dbf
    命令转换为
    dbf2txt-C7-C9-C5-C9-d,-d,file.dbf-file.att
    我没有使用这些命令,所以我不知道。它可能需要一些额外的注意,例如,C9字段将有9个字符,即使最后几个字符只是空格。根据您的输入文件的外观,这可能很好--也许您可以发布一些输入文本文件的示例行?似乎从dbf文件重建文本文件然后重新转换可能更容易--您尝试过了吗?谢谢,Ethan。不,我没想到要试试这个。。看起来可能是一张越狱卡。。这是不是将我使用的
    txt2dbf-C7-C9-C5-C9-d,-d,-d,file.att file.dbf
    命令转换为
    dbf2txt-C7-C9-C5-C9-d,-d,file.dbf-file.att
    我没有使用这些命令,所以我不知道。它可能需要一些额外的注意,例如,C9字段将有9个字符,即使最后几个字符只是空格。根据您的输入文件的外观,这可能很好——也许您可以发布一些输入文本文件的示例行?这看起来很有希望——感谢上面的代码。我试图运行第一个代码块来恢复原始文本,但当使用
    data[16:][.strip()
    或常见错误
    dbf.ver\u 2.BadDataError:记录数据的长度不正确(应该是31,而不是30)时,我得到了错误
    AttributeError:'array.array'对象没有属性'strip'
    当我#取出.strip()部分(分别)时,我也尝试在示例文本文件上运行第二块代码,但我得到了以下错误:
    dbf.ver_2.dbferor:传入数据的值太多了。
    。啊,很抱歉。更新的代码片段。第一个代码片段现在就可以工作了-我可以用每一行生成一个文本文件,如下所示:1001201092300,7。。问题是第一条记录丢失,因此文本文件不是从1000201201100000开始的……将恢复的.txt转换为.dbf的第二个代码段似乎工作得很好(谢谢!)——但第一个代码段的第一条记录丢失正在传播到最终的dbf(如您所料)。这似乎真的很有希望-感谢上面的代码。我试图运行第一个代码块来恢复原始文本,但得到了错误
    AttributeError:'array.array'对象