0

.assocで終わるファイルがあり、明らかに「バイナリ関連ファイル」ですが、この種のファイルに関する情報はオンラインで見つかりません。それはfortranとidlによって読み取られ、49Mbであり、私はそれをpythonに読み込もうとしています。これはおそらく未解決の質問ですが、ファイルの構造を調べて、どのように読み取ることができるかを知る方法を誰かが提案できますか?

このファイルは、火星の標高の地図(おそらく2D)であることを私は知っています。そしてそれは短いASCIIヘッダーを持っています:

        7200         3600 MOLA .05 dg/px topo 5/2002

---------------------------------------------------------

header length        14400 bytes

map X size                7200

map Y size                3600

no-data value            30303

maximum value            21197

minimum value            -8204

The map is stored as an INT array with X as

longitude and Y as latitude. The map is assumed to be

global in coverage.

--------------------------------------------------------- 

不正な形式の質問で申し訳ありませんが、不明なファイルタイプをプローブする方法に関する一般的なアドバイスをいただければ幸いです。または、このファイルタイプを知っている場合は、さらに良いでしょう!

ファイルを読み取るidlコードのスニペットは次のとおりです。

ELMAP='elevmap.assoc'
OPENR, ELUN, ELMAP, /GET_LUN
B = ASSOC(ELUN,BYTARR(100))              ; assoc header
HEADER = STRING(B[0])                    ; read the header
NLON = 0                                 ; 'fix' no. of longitudes
NLAT = 0                                 ; 'fix' no. of latitudes
READS,HEADER,NLON,NLAT                   ;  read no. of lons/lats
EXG = NLON/360                           ; longitude scale (pix/deg)
EYG = NLAT/180                           ; latitude scale (pix/deg)
EMAP = ASSOC(ELUN,INTARR(1),14400)

最初の30バイトの16進ダンプ(「od-H -N 30elevmap.assoc」を実行しました)は次のようになります。

0000000          20202020        20202020        30303237        20202020
0000020          20202020        30363320        4f4d2030        0000414c
0000036

ヘッダーの後の最初の30バイトの16進ダンプ( "od -H -j 14400 -N 30 elevmap.assoc"、これを誤解している場合はお知らせください)は次のようになります。

0034100          0e970e93        0ea50e9d        0ea50ea5        0ea50ea5
0034120          0ea50ea5        0ea40ea4        0ea20ea3        00000ea2
0034136
4

5 に答える 5

4

最初の 30 バイトの 16 進ダンプ (「od -H -N 30 elevmap.assoc」を実行しました) は次のようになります。

0000000          20202020        20202020        30303237        20202020
0000020          20202020        30363320        4f4d2030        0000414c
0000036

これらは明らかにリトル エンディアンで格納されるため、各バイト シーケンスを逆にする必要があります。ここでは、それを ASCII に翻訳しました。

0000000          20 20 20 20 20 20 20 20 37 32 30 30 20 20 20 20
                  _  _  _  _  _  _  _  _  7  2  0  0  _  _  _  _
0000020          20 20 20 20 20 33 36 30 30 20 4d 4f 4c 41
                  _  _  _  _  _  3  6  0  0  _  M  O  L  A

ヘッダーの後の最初の 30 バイトの 16 進ダンプ ("od -H -j 14400 -N 30 elevmap.assoc"、これを誤解している場合はお知らせください) は次のようになります。

0034100          0e970e93        0ea50e9d        0ea50ea5        0ea50ea5
0034120          0ea50ea5        0ea40ea4        0ea20ea3        00000ea2

ヘッダーには、7200 x 3600 の INT 値があることが示されています。INTの大きさは?INT がintほとんどの Unix システム (4 バイト) と同じくらい大きい場合、ファイルの合計サイズは7200 x 3600 x 499 MiB またはほぼ 99 MiB になります。あなたはそれが49 MiBであると言っているので、圧縮が使用されている(可能性は低い)か、INTが16ビットである(可能性が高い)のいずれかです。後者の強力な証拠は、この秒から得られるものですod.32ビット整数0e970e93に非常によく似0e97ており、誤って連結されているように見えます. 0e93地形図から、隣接する値が急激に変化しないことが予想されます (深い垂直のトレンチまたは急な山の壁の境界を除く)。これは、値が の範囲内にあるという事実とも一致していますshort int: [-32768, 32767]

この知識があれば、上記のダンプは次のように読む必要があります。

0034100          0e93  0e97  0e9d  0ea5  0ea5  0ea5  0ea5  0ea5
                +3731 +3735 +3741 +3749 +3749 +3749 +3749 +3749
0034120          0ea5  0ea5  0ea4  0ea4  0ea3  0ea2  0ea2
                +3749 +3749 +3748 +3748 +3747 +3746 +3746

これで、X メジャーまたは Y メジャーのデータ ストレージが使用されたかどうかを確認するだけで済みます。私の経験では、ほとんどのデータ処理ツールは Fortran の列優先順に従います。データが の場合DATA(X,Y)、X が主要な次元になる必要があります。つまり、必然的なデータ値は 、、、DATA(1,Y)... 、、、DATA(2,Y)などになります。 PIL またはその他の Python 用の画像操作パッケージを調べて、地形図や乱雑なものに似たものが得られるかどうかを確認してください。DATA(3,Y)DATA(1,Y+1)DATA(2,Y+1)

struct.unpack()mgilson の提案に従ってデータをアンパックする場合はh、signed short integer 値の形式を使用する必要があります。

data = struct.unpack('%dh' % (7200*3600), f.read(7200*3600*2))
于 2012-07-10T16:32:56.790 に答える
2

よろしくお願いします。特に、有用なコードテンプレートのhexdump出力とmgilsonの優れた説明についてはHristoIliev。

完全を期すために、他の誰かがassocファイルを読み込もうとしてこの投稿につまずくという偶然の機会に、これが私のために働いたpythonコードです。

import struct
import numpy as np
import matplotlib.pylab as pl

with open('elevmap.assoc','rb') as f:
    f.read(14400)
    data=struct.unpack('%dh' % (7200*3600), f.read(7200*3600*2))

# Now turn it into a numpy array
data = np.array(data).reshape(3600,7200)

pl.figure()
pl.imshow(data)
pl.show()

これはこのかわいい地図を返しました:火星の標高

火星です、南は上がっています、しかしそれは修正するのは簡単です。どうもありがとうございました。

于 2012-07-10T18:22:37.890 に答える
2

次に、Fortranがフォーマットされていないファイルを書き込む方法について説明するいくつかの質問があります。Fortranのフォーマットされていないファイル形式またはPythonでの直接アクセスfortranのフォーマットされていないファイルの読み取り。余分なバイトがどこにあるかを知るには、Fortranで使用された読み取りステートメントを知る必要があります。これにより、レコード構造がわかります。最近のFortranでは、StreamIOを使用して余分なバイトをバイパスできます。16進エディタを使用すると、これらの側面をリバースエンジニアリングできます。

エンディアンは通常、Fortranでは指定できません。16進エディタで推測できるもう1つの側面。Gfortranには、エンディアンを指定するための拡張機能があります。

于 2012-07-10T02:15:03.530 に答える
1

これは私が今まで見たファイル形式ではありませんが、ヘッダーの情報に基づいて、次のようなことができる可能性があります。

import numpy as np
import struct

with open('datafile.assoc','rb') as f:
    nx,ny=f.read(14400).split()[:2]  #here I split the header and only take the array indices.  You could get more fancy with your parsing if you wanted.
    data=struct.upack('%dh'%(nx*ny),f.read(nx*ny*2))

#now turn it into a numpy array:
data = np.array(data).reshape(ny,nx)  #assume "x" is the fast index
data[data==30303] = np.nan
#some checks
print (np.nanmax(data)) # 21197
print (np.nanmin(data)) # -8204

それが機能せず、ファイルを生成した fortran コード (またはファイルを読み取ることができる fortran コード) がある場合は、それも役に立ちます。

于 2012-07-10T00:17:21.767 に答える
1

ヘッダーによると、データは 7200 x 3600 の INT の配列として保存されます。

最小値は負であるため、おそらく 16 ビットまたは 32 ビットの符号付き整数です。(残りのファイルのサイズ) / (7200 * 3600) は、バイト単位の 1 つの int のサイズである必要があります。

残りの質問:

  • バイト エンディアン (つまり、623 は 00 00 02 6f (ビッグ エンディアン) または 6f 02 00 00 (リトル エンディアン) として保存できます)

  • 行ごとまたは列ごと - 両方を試して、どちらが正しいかを確認してください

ファイル全体のサイズと、最初の 30 バイトのデータの 16 進ダンプを提供していただけると、非常に助かります。

于 2012-07-10T00:23:49.357 に答える