我最近在unix系统上从大气模型(HYSPLIT)生成了数千个shapefile输出和附带的.dbf文件。转换器txt2dbf
用于将shapefile属性表(文本文件)转换为.dbf。
不幸的是,出现了错误(可能是分隔符/字段长度错误),因为输出.dbf文件存在2个问题,如下所示:
这是输出dbf中第一条记录的示例(使用dbview
unix包检索):
Trajnum:1001 2
Yyyymmdd:0111231 2
时间:300
等级:0 1000 201:
这就是我的预期:
Trajnum:1000
Yyyymmdd:20111231
时间:2300
等级:0。
另外,我正在考虑如何防止这种情况再次发生,但理想情况下,我希望能够修复现有的.dbf文件。不幸的是,每个模型运行都删除了文本文件,因此"修复" .dbf文件是唯一的选择。
我解决上述问题的方法是:
dbf.add_fields
和dbf.write
(python包dbf
)从新变量中存在的字段中提取信息,然后使用dbf.delete_fields
删除旧的错误字段。 这是我尝试过的:
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文件:
答案 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))