Открыть / редактировать заголовок utf8 в Python (pyfits)
Мне приходится иметь дело с некоторыми файлами подгонки, которые содержат в заголовке текст utf8. Это означает, что в основном все функции пакета pyfits не работают. Также .decode не работает, так как заголовок соответствия - это класс, а не список. Кто-нибудь знает, как декодировать заголовок, чтобы я мог обработать данные? Фактическое содержание не так важно, так что игнорирование букв - это нормально. Мой текущий код выглядит так:
hdulist = fits.open('Jupiter.FIT')
hdu = hdulist[0].header
hdu.decode('ascii', errors='ignore')
И я получаю: AttributeError: объект 'Header' не имеет атрибута 'decode'
Функции, такие как:
print (hdu)
вернуть:
ValueError: FITS header values must contain standard printable ASCII characters; "'Uni G\xf6ttingen, Institut f\xfcr Astrophysik'" contains characters/bytes that do not represent printable characters in ASCII.
Я думал о том, чтобы написать что-то в записи, поэтому мне не нужно заботиться об этом. Однако я даже не могу определить, какая запись содержит плохие символы, и я хотел бы иметь пакетное решение, поскольку у меня есть несколько сотен файлов.
2 ответа
Как отметил Анатолий Техтоник , не-ASCII-символы в заголовках FITS являются недопустимыми и создают недопустимые файлы FITS. Тем не менее, было бы хорошо, если astropy.io.fits
мог бы по крайней мере прочитать недействительные записи. Поддержка этого в настоящее время нарушена и нуждается в защитнике, чтобы исправить это, но никто не имеет, потому что это достаточно редкая проблема, и большинство людей сталкиваются с ней в одном или двух файлах, исправляют эти файлы и идут дальше. Хотелось бы, чтобы кто-то решил эту проблему.
Между тем, поскольку вы точно знаете, на какую строку этот файл работает, я просто открыл файл в двоичном режиме и заменил строку. Если файл FITS очень большой, вы можете прочитать его за раз и выполнить замену этих блоков. Файлы FITS (особенно заголовки) записываются в блоках по 2880 байт, так что вы знаете, что в любом месте эта строка будет выровнена по такому блоку, и вам не нужно ничего анализировать в формате заголовка, кроме этого. Просто убедитесь, что строка, которой вы ее заменяете, не длиннее исходной строки и что, если она короче, она дополняется пробелами справа, потому что заголовки FITS имеют формат фиксированной ширины, и все, что изменяет длину заголовка, будет повредить весь файл. Тогда для этого конкретного случая я бы попробовал что-то вроде этого:
bad_str = 'Uni Göttingen, Institut für Astrophysik'.encode('latin1')
good_str = 'Uni Gottingen, Institut fur Astrophysik'.encode('ascii')
# In this case I already know the replacement is the same length so I'm no worried about it
# A more general solution would require fixing the header parser to deal with non-ASCII bytes
# in some consistent manner; I'm also looking for the full string instead of the individual
# characters so that I don't corrupt binary data in the non-header blocks
in_filename = 'Jupiter.FIT'
out_filename = 'Jupiter-fixed.fits'
with open(in_filename, 'rb') as inf, open(out_filename, 'wb') as outf:
while True:
block = inf.read(2880)
if not block:
break
block = block.replace(bad_str, good_str)
outf.write(block)
Это некрасиво, и для очень большого файла это может быть медленно, но это только начало. Я могу придумать лучшие решения, но их сложнее понять, и, вероятно, не стоит тратить время, если вам нужно исправить несколько файлов.
После того, как это будет сделано, пожалуйста, строго сообщите отправителю файла - они не должны публиковать поврежденные файлы FITS.
Похоже PyFITS
просто не поддерживает это (пока?)
С https://github.com/astropy/astropy/issues/3497:
FITS предшествует Unicode и никогда не обновлялся для поддержки чего-либо, кроме печатных символов ASCII для данных. Невозможно кодировать символы не ASCII в заголовках FITS.