2017-02-09 12 views
1

Недавно я выпустил несколько тысяч выходных файлов шейп-файлов и сопровождающие файлы .dbf из атмосферной модели (HYSPLIT) в системе unix. Конвертер txt2dbf используется для преобразования таблиц атрибутов shapefile (текстового файла) в .dbf.BadDataError при редактировании .dbf-файла с использованием пакета dbf

К сожалению, что-то пошло не так (возможно, разделитель/поле ошибка длины), потому что есть 2 проблемы с выходом .dbf файлов следующим образом:

  1. Некоторые поля в DBF содержат данные, которые не должны будь там. Эти данные «пролились» из соседних полей.
  2. Добавлено дополнительное поле, которое не должно быть там (оно действительно происходит из раздела первой записи текстового файла «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-файлов является единственным вариантом.

Мои подходы к выше проблем являются:

  1. Извлечение информации из полей, которые существуют в новую переменную с помощью dbf.add_fields и dbf.write (Python пакет dbf), а затем удалите старые неправильные поля с помощью dbf.delete_fields.
  2. Удалить ненужное дополнительное поле.

Это то, что я пробовал:

 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 преобразования, я m не удивлен, обнаружив ошибку в длине данных записи. Однако это означает, что файл полностью поврежден и что я не могу извлечь нужную мне информацию (разочарование, потому что я вижу, что она существует)?


EDIT:

Вместо того, чтобы пытаться изменить «плохие» .dbf файлы, кажется, лучший подход к 1. экстракту необходимых данных в текст из плохих файлов, а затем 2. записи к новому dbf. (См. Комментарии и ответ Итана Фурмана ниже).


РЕДАКТИРОВАТЬ:

Пример неисправной.DBF файл, который мне нужно исправить/восстановить данные можно найти здесь:

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

Пример .txt файла, из которого можно найти здесь дефектные DBF файлы были созданы:

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

+0

Похоже, что может быть проще восстановить текстовый файл из файла dbf, а затем переконвертировать - вы пробовали? –

+0

Спасибо, Этан. Нет, я не думал попробовать это .. похоже, что это может быть карта раздачи. Это будет случай обращения к команде 'txt2dbf', которую я использовал' txt2dbf -C7 -C9 -C5 -C9 -d, -d, -d, file.att file.dbf' в 'dbf2txt -C7 -C9 -C5 -C9 -d, -d, -d, file.dbf file.att' –

+0

У меня нет использовал эти команды, поэтому я не знаю. Это может занять некоторую дополнительную заботу, так как поле C9, например, будет иметь 9 символов, даже если последние несколько являются просто пробелами. В зависимости от того, как выглядел ваш входной файл, это может быть хорошо - возможно, вы могли бы опубликовать несколько строк примера входного текстового файла? –

ответ

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

Это кажется действительно многообещающим - спасибо за код выше. Я попытался запустить первый блок кода, чтобы восстановить исходный текст, но я получаю сообщение об ошибке. Объект AttributeError: 'array.array' не имеет атрибута 'strip'', когда 'data [16:]. Strip()' is используется или знакомая ошибка 'dbf.ver_2.BadDataError: запись данных не является правильной длиной (должно быть 31, а не 30)', когда я # из .strip(). –

+0

(Отдельно) Я также попытался запустить второй блок кода в текстовом файле примера, но я получаю следующую ошибку: 'dbf.ver_2.DbfError: входящие данные имеют слишком много значений'. –

+0

А, простите об этом. Обновлены фрагменты. –