如何使用 astropy.io.fits.open() 打开远程 .FTS.gz 文件?
How to open a remote .FTS.gz file with astropy.io.fits.open()?
问题总结:
我正在编写一些代码,使用 astropy.io.fits 检查 FTS 文件头的内容(从 telescope 保存的数据)。我的问题是当我尝试在远程服务器上打开 .FTS.gz 文件而不是 .FTS 文件时。当我 open()
a .FTS.gz 我得到错误,如果我 gunzip
.FTS.gz 文件,一切都很好。其中一个错误表明我有一张 END 丢失的卡片。在线搜索,我使用了在 fits.open()
中使用 ignore_missing_end=True
参数的建议,但随后出现下一个错误。下一个错误表明我的 FITS 文件为空或损坏,但事实并非如此。我可以用 SAOImage DS9 打开它没有任何问题,而且我有 运行 this handy online tool called fitsverify
which reports no errors in my file. If I download the offending file .FTS.gz and run a similar code to fits.open()
this file locally, I get no errors at all. An example of an offending file (used in the code below) is now uploaded here.
Astropy 文档说:
“使用压缩文件
open()
功能将无缝打开使用 gzip、bzip2 或 pkzip 压缩的 FITS 文件。请注意,在这种情况下,我们讨论的是已使用这些实用程序之一压缩的适合文件 - 例如一个 .fits.gz 文件。
如何在不下载的情况下打开远程 .FTS.gz 文件?我有成百上千个这样的文件,所以下载不是一种选择,而且不是只有一个文件有问题,而是所有文件都有问题。
谢谢,
艾娜.
代码和错误:
远程打开代码。FTS.gz文件:
from astropy.io import fits
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect('myhostname', username='myusername', password='mypassword')
apath = '/path/to/folder/to/search'
apattern = '"RUN0001.FTS.gz"'
rawcommand = 'find {path} -name {pattern}'
command = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = client.exec_command(command)
filelist = stdout.read().splitlines()
for i in filelist:
sftp_client = client.open_sftp()
remote_file = sftp_client.open(i)
hdulist = fits.open(remote_file)
client.close()
错误:
Traceback (most recent call last):
File "/Users/amusaeva/Documents/PyCharm/FITSHeaders/Whosebug.py", line 17, in <module>
hdulist = fits.open(remote_file)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 166, in fitsopen
lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 404, in fromfile
lazy_load_hdus=lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1040, in _readfrom
read_one = hdulist._read_next_hdu()
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1135, in _read_next_hdu
hdu = _BaseHDU.readfrom(fileobj, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/base.py", line 329, in readfrom
**kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/base.py", line 394, in _readfrom_internal
header = Header.fromfile(data, endcard=not ignore_missing_end)
File "/Library/Python/2.7/site-packages/astropy/io/fits/header.py", line 450, in fromfile
padding)[1]
File "/Library/Python/2.7/site-packages/astropy/io/fits/header.py", line 519, in _from_blocks
raise IOError('Header missing END card.')
IOError: Header missing END card.
Process finished with exit code 1
仅更改一行以上代码:
hdulist = fits.open(remote_file, ignore_missing_end=True)
错误:
WARNING: VerifyWarning: Error validating header for HDU #0 (note: Astropy uses zero-based indexing).
Header size is not multiple of 2880: 7738429
There may be extra bytes after the last HDU or the file is corrupted. [astropy.io.fits.hdu.hdulist]
Traceback (most recent call last):
File "/Users/amusaeva/Documents/PyCharm/FITSHeaders/Whosebug.py", line 17, in <module>
hdulist = fits.open(remote_file, ignore_missing_end=True)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 166, in fitsopen
lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 404, in fromfile
lazy_load_hdus=lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1044, in _readfrom
raise IOError('Empty or corrupt FITS file')
IOError: Empty or corrupt FITS file
Process finished with exit code 1
打开有问题的代码。FTS.gz 本地文件没有产生错误:
import os
from astropy.io import fits
folderTosearch = "/path/to/folder/to/search/locally";
for root, dirs, files in os.walk(folderTosearch):
for file in files:
if file.endswith("RUN0001.FTS.gz"):
hdulist = fits.open(os.path.join(root, file))
发生这种情况是因为 sftp 调用传递了类文件对象的某些变体(它具有 fits.open()
将使用的 .read()
方法。
然而,类似对象的文件仍然是一个 gzip 文件。 Astropy 检查文件是否压缩 only for file names,也就是说,当 fits.open()
的参数是一个字符串时(发生这种情况成为一条道路)。 Astropy 似乎没有测试将字节流标识为 gzip 文件的魔术字节。奇怪的是,它确实在传递路径字符串时进行此验证。可以说,这可能是 astropy.io.fits 模块中的一个小缺点,但也许是有原因的。
(免责声明:以上结论是快速浏览the relevant source code得出的;我可能遗漏了一些东西。如果是这样,希望人们能纠正我。)
一种解决方案是自己解压缩。我拼凑了以下内容:
from cStringIO import StringIO
import zlib
<...>
for i in filelist:
sftp_client = client.open_sftp()
remote_file = sftp_client.open(i)
decompressed = StringIO(
zlib.decompress(remote_file.read(), zlib.MAX_WBITS|32))
hdulist = fits.open(decompressed)
client.close()
上面,我们正在读取远程文件的全部内容(remote_file.read()
,然后解压缩内容。结果是一个字符串,所以我们将它包装在一个 StringIO
实例中以制作它又是一个类似文件的对象,我们可以将其传递给 fits.open()
。(对于 zlib.MAX_WBITS|32
参数:参见 this answer。)
或者,您可以将文件sftp 到本地磁盘,然后在本地读取文件(使用本地文件名)。以上只是将所有内容保存在内存中。
问题总结:
我正在编写一些代码,使用 astropy.io.fits 检查 FTS 文件头的内容(从 telescope 保存的数据)。我的问题是当我尝试在远程服务器上打开 .FTS.gz 文件而不是 .FTS 文件时。当我 open()
a .FTS.gz 我得到错误,如果我 gunzip
.FTS.gz 文件,一切都很好。其中一个错误表明我有一张 END 丢失的卡片。在线搜索,我使用了在 fits.open()
中使用 ignore_missing_end=True
参数的建议,但随后出现下一个错误。下一个错误表明我的 FITS 文件为空或损坏,但事实并非如此。我可以用 SAOImage DS9 打开它没有任何问题,而且我有 运行 this handy online tool called fitsverify
which reports no errors in my file. If I download the offending file .FTS.gz and run a similar code to fits.open()
this file locally, I get no errors at all. An example of an offending file (used in the code below) is now uploaded here.
Astropy 文档说:
“使用压缩文件
open()
功能将无缝打开使用 gzip、bzip2 或 pkzip 压缩的 FITS 文件。请注意,在这种情况下,我们讨论的是已使用这些实用程序之一压缩的适合文件 - 例如一个 .fits.gz 文件。
如何在不下载的情况下打开远程 .FTS.gz 文件?我有成百上千个这样的文件,所以下载不是一种选择,而且不是只有一个文件有问题,而是所有文件都有问题。
谢谢, 艾娜.
代码和错误:
远程打开代码。FTS.gz文件:
from astropy.io import fits
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect('myhostname', username='myusername', password='mypassword')
apath = '/path/to/folder/to/search'
apattern = '"RUN0001.FTS.gz"'
rawcommand = 'find {path} -name {pattern}'
command = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = client.exec_command(command)
filelist = stdout.read().splitlines()
for i in filelist:
sftp_client = client.open_sftp()
remote_file = sftp_client.open(i)
hdulist = fits.open(remote_file)
client.close()
错误:
Traceback (most recent call last):
File "/Users/amusaeva/Documents/PyCharm/FITSHeaders/Whosebug.py", line 17, in <module>
hdulist = fits.open(remote_file)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 166, in fitsopen
lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 404, in fromfile
lazy_load_hdus=lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1040, in _readfrom
read_one = hdulist._read_next_hdu()
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1135, in _read_next_hdu
hdu = _BaseHDU.readfrom(fileobj, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/base.py", line 329, in readfrom
**kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/base.py", line 394, in _readfrom_internal
header = Header.fromfile(data, endcard=not ignore_missing_end)
File "/Library/Python/2.7/site-packages/astropy/io/fits/header.py", line 450, in fromfile
padding)[1]
File "/Library/Python/2.7/site-packages/astropy/io/fits/header.py", line 519, in _from_blocks
raise IOError('Header missing END card.')
IOError: Header missing END card.
Process finished with exit code 1
仅更改一行以上代码:
hdulist = fits.open(remote_file, ignore_missing_end=True)
错误:
WARNING: VerifyWarning: Error validating header for HDU #0 (note: Astropy uses zero-based indexing).
Header size is not multiple of 2880: 7738429
There may be extra bytes after the last HDU or the file is corrupted. [astropy.io.fits.hdu.hdulist]
Traceback (most recent call last):
File "/Users/amusaeva/Documents/PyCharm/FITSHeaders/Whosebug.py", line 17, in <module>
hdulist = fits.open(remote_file, ignore_missing_end=True)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 166, in fitsopen
lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 404, in fromfile
lazy_load_hdus=lazy_load_hdus, **kwargs)
File "/Library/Python/2.7/site-packages/astropy/io/fits/hdu/hdulist.py", line 1044, in _readfrom
raise IOError('Empty or corrupt FITS file')
IOError: Empty or corrupt FITS file
Process finished with exit code 1
打开有问题的代码。FTS.gz 本地文件没有产生错误:
import os
from astropy.io import fits
folderTosearch = "/path/to/folder/to/search/locally";
for root, dirs, files in os.walk(folderTosearch):
for file in files:
if file.endswith("RUN0001.FTS.gz"):
hdulist = fits.open(os.path.join(root, file))
发生这种情况是因为 sftp 调用传递了类文件对象的某些变体(它具有 fits.open()
将使用的 .read()
方法。
然而,类似对象的文件仍然是一个 gzip 文件。 Astropy 检查文件是否压缩 only for file names,也就是说,当 fits.open()
的参数是一个字符串时(发生这种情况成为一条道路)。 Astropy 似乎没有测试将字节流标识为 gzip 文件的魔术字节。奇怪的是,它确实在传递路径字符串时进行此验证。可以说,这可能是 astropy.io.fits 模块中的一个小缺点,但也许是有原因的。
(免责声明:以上结论是快速浏览the relevant source code得出的;我可能遗漏了一些东西。如果是这样,希望人们能纠正我。)
一种解决方案是自己解压缩。我拼凑了以下内容:
from cStringIO import StringIO
import zlib
<...>
for i in filelist:
sftp_client = client.open_sftp()
remote_file = sftp_client.open(i)
decompressed = StringIO(
zlib.decompress(remote_file.read(), zlib.MAX_WBITS|32))
hdulist = fits.open(decompressed)
client.close()
上面,我们正在读取远程文件的全部内容(remote_file.read()
,然后解压缩内容。结果是一个字符串,所以我们将它包装在一个 StringIO
实例中以制作它又是一个类似文件的对象,我们可以将其传递给 fits.open()
。(对于 zlib.MAX_WBITS|32
参数:参见 this answer。)
或者,您可以将文件sftp 到本地磁盘,然后在本地读取文件(使用本地文件名)。以上只是将所有内容保存在内存中。