使用 dbf 包编辑 .dbf 文件时出现 BadDataError
BadDataError when editing a .dbf file using dbf package
我最近在 unix 系统上从大气模型 (HYSPLIT) 生成了数千个 shapefile 输出和随附的 .dbf 文件。转换器 txt2dbf
用于将 shapefile 属性表(文本文件)转换为 .dbf。
不幸的是,出了点问题(可能是 separator/field 长度错误),因为输出的 .dbf 文件有 2 个问题,如下:
- dbf 的某些字段包含不应存在的数据。此数据已从相邻字段“溢出”。
- 添加了一个不应该存在的附加字段(它实际上来自文本文件第一条记录的一部分,“1000 201”)。
这是输出 dbf 中第一条记录的示例(使用 dbview
unix 包检索):
Trajnum : 1001 2
Yyyymmdd : 0111231 2
Time : 300
Level : 0.
1000 201:
这是我的预期:
Trajnum : 1000
Yyyymmdd : 20111231
Time : 2300
Level : 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
转换存在的明显问题,我发现记录数据长度存在错误并不奇怪。但是,这是否意味着该文件已完全损坏并且我无法提取我需要的信息(令人沮丧,因为我可以看到它存在)?
编辑:
与其尝试编辑 'bad'.dbf 文件,这似乎是一种更好的方法:1. 从坏文件中将所需数据提取到文本中,然后 2. 写入新的 dbf。 (参见下面 Ethan Furman 的 comments/answer)。
编辑:
我需要 fix/recover 数据的错误 .dbf 文件示例可在此处找到:
https://www.dropbox.com/s/9y92f7m88a8g5y4/p0001120110.dbf?dl=0
可在此处找到创建错误 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')
假设您所有的数据文件看起来都像您的示例(大 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))
我最近在 unix 系统上从大气模型 (HYSPLIT) 生成了数千个 shapefile 输出和随附的 .dbf 文件。转换器 txt2dbf
用于将 shapefile 属性表(文本文件)转换为 .dbf。
不幸的是,出了点问题(可能是 separator/field 长度错误),因为输出的 .dbf 文件有 2 个问题,如下:
- dbf 的某些字段包含不应存在的数据。此数据已从相邻字段“溢出”。
- 添加了一个不应该存在的附加字段(它实际上来自文本文件第一条记录的一部分,“1000 201”)。
这是输出 dbf 中第一条记录的示例(使用 dbview
unix 包检索):
Trajnum : 1001 2
Yyyymmdd : 0111231 2
Time : 300
Level : 0.
1000 201:
这是我的预期:
Trajnum : 1000
Yyyymmdd : 20111231
Time : 2300
Level : 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
转换存在的明显问题,我发现记录数据长度存在错误并不奇怪。但是,这是否意味着该文件已完全损坏并且我无法提取我需要的信息(令人沮丧,因为我可以看到它存在)?
编辑:
与其尝试编辑 'bad'.dbf 文件,这似乎是一种更好的方法:1. 从坏文件中将所需数据提取到文本中,然后 2. 写入新的 dbf。 (参见下面 Ethan Furman 的 comments/answer)。
编辑:
我需要 fix/recover 数据的错误 .dbf 文件示例可在此处找到:
https://www.dropbox.com/s/9y92f7m88a8g5y4/p0001120110.dbf?dl=0
可在此处找到创建错误 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')
假设您所有的数据文件看起来都像您的示例(大 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))