用python进行二进制阅读会产生意外的结果

问题描述 投票:1回答:1

我正在尝试使用python读取一些二进制文件,以进行Zemax OpticStudio生成的分析。该文件的结构应该如下:

  • 2 x 32位整数作为标题
  • n个数据块

每个块由]制成>

  • 32位整数,表示之后的C struc数
  • m C结构
  • 结构的定义如下:

typedef struct
{
unsigned int status;
int level;
int hit_object;
int hit_face;
int unused;
int in_object;
int parent;
int storage;
int xybin, lmbin;
double index, starting_phase;
double x, y, z;
double l, m, n;
double nx, ny, nz;
double path_to, intensity;
double phase_of, phase_at;
double exr, exi, eyr, eyi, ezr, ezi;
}

为了方便起见,其大小为208个字节。

这是我通过一些研究编写的代码,并从此处获得了两个绝妙的答案。


from pathlib import Path
from functools import partial
from io import DEFAULT_BUFFER_SIZE
import struct

def little_endian_int(x):
    return int.from_bytes(x,'little')

def file_byte_iterator(path):
    """iterator over lazily loaded file
    """
    path = Path(path)
    with path.open('rb') as file:
        reader = partial(file.read1, DEFAULT_BUFFER_SIZE)
        file_iterator = iter(reader, bytes())
        for chunk in file_iterator:
            yield from chunk

def ray_tell(rays_idcs:list,ray_idx:int,seg_idx:int):
    idx = rays_idcs[ray_idx][0]
    idx += 4 + 208*seg_idx
    return idx


def read_header(bytearr:bytearray):
    version = int.from_bytes(bytearr[0:4],'little')
    zrd_format = version//10000
    version = version%10000
    num_seg_max = int.from_bytes(bytearr[4:8],'little')
    return zrd_format,version,num_seg_max


def rays_indices(bytearr:bytearray):
    index=8
    rays=[]
    while index <len(bytearr):
        num_seg = int.from_bytes(bytearr[index:index+4],'little')
        rays.append((index,num_seg))
        index = index+4 + 208*num_seg
    return rays

def read_ray(bytearr:bytearray,ray):
    ray_idx,num_seg = ray
    data = []
    ray_idx = ray_idx + 4
    seg_idx=0
    for ray_idx in range(8,8+num_seg*208,208):
        offsets = [0,4,8,12,16,20,24,28,32,36,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200]
        int_vars = offsets[0:11]
        doubl_vars = offsets[11:]
        data_integ = [bytearr[ray_idx+offset:ray_idx+offset+4] for offset in int_vars]
        data_doubl = [bytearr[ray_idx+offset:ray_idx+offset+8] for offset in doubl_vars]

        data.append([seg_idx,data_integ,data_doubl])
        seg_idx += 1
    return data



file="test_uncompressed.ZRD"

raypath = {}
filebin = bytearray(file_byte_iterator(file))
header = read_header(filebin)
print(header)
rays_idcs = rays_indices(filebin)
rays = []
for ray in rays_idcs:
    rays.append(read_ray(filebin,ray))
ray = rays[1] #Random ray
segm = ray[2] #Random segm
ints = segm[1]
doub = segm[2]
print("integer vars:")
for x in ints:
    print(x,little_endian_int(x))
print("double vars:")
for x in doub:
    print(x,struct.unpack('<d',x))     

我已验证所有结构都具有正确的大小和块和结构的数量(我的读数与我使用Zemax读取的段和射线的数量相匹配),并感谢标头,我验证了结构的字节序文件(小端)。我的输出如下:

(0, 2002)
bytearray(b'\x1f\xd8\x9c?') 1067243551
bytearray(b'\x06\x80\x00\x00') 32774
bytearray(b'\x02\x00\x00\x00') 2
bytearray(b'\x11\x00\x00\x00') 17
bytearray(b'\x02\x00\x00\x00') 2
bytearray(b'\x00\x00\x00\x00') 0
bytearray(b'\x11\x00\x00\x00') 17
bytearray(b'\x01\x00\x00\x00') 1
bytearray(b'\x00\x00\x00\x00') 0
bytearray(b'\x00\x00\x00\x00') 0
double vars:
bytearray(b'\x00\x00\x00\x00# \xac\xe8') (-1.6425098109028998e+196,)
bytearray(b'\xe8\xe3\xf9?\x00\x00\x00\x00') (5.3030112e-315,)
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') (0.0,)
bytearray(b'\x00\x00\x00\x00p_\xb4\xec') (-4.389425605765071e+215,)
bytearray(b'5\xe3\x9d\xbf\xf0\xbd"\xa2') (-3.001836066957746e-144,)
bytearray(b'z"\xc0?\x00\x00\x00\x00') (5.28431047e-315,)
bytearray(b'\x00\x00\x00\x00 \xc9+\xa3') (-2.9165705864036956e-139,)
bytearray(b'g\xd4\xcd?\x9ch{ ') (3.2707669223572687e-152,)
bytearray(b'q\x1e\xef?\x00\x00\x00\x00') (5.299523535e-315,)
bytearray(b'\x00\x00\x00\x00%\x0c\xb4A') (336340224.0,)
bytearray(b'\t\xf2u\xbf\\3L\xe6') (-5.991371249309652e+184,)
bytearray(b'\xe1\xff\xef\xbf1\x8dV\x1e') (1.5664573023148095e-162,)
bytearray(b'\xa1\xe9\xe8?\x9c\x9a6\xfc') (-2.202825582975923e+290,)
bytearray(b'qV\xb9?\x00\x00\x00\x00') (5.28210966e-315,)
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') (0.0,)
bytearray(b'\x00\x00\x00\x00\xc6\xfd\x0c\xa1') (-1.7713316840526727e-149,)
bytearray(b'\x96\x94\x8d?\xad\xf9(\xcc') (-7.838624888507203e+58,)
bytearray(b'yN\xb2\xbff.\\\x1a') (1.0611651097687064e-181,)
bytearray(b'\xb9*\xae?\xac\xaf\xe5\xe1') (-3.90257774261585e+163,)
bytearray(b'c\xab\xd2\xbf\xccQ\x8bj') (1.7130904564012918e+205,)
bytearray(b'\xc8\xea\x8c\xbf\xdf\xdc\xe49') (8.22891935818188e-30,)

我正在正确地读取int值。我不明白为什么我要为所有其他变量获取这些二进制文件

编辑

我想强调字节数组包含非十六进制数字,并且我确定二进制文件没有损坏,因为我可以在zemax中读取它们。

我正在尝试使用python读取一些二进制文件,以进行Zemax OpticStudio生成的分析。该文件的结构应为以下形式:2 x 32位整数,作为标头的n个块,...

python binaryfiles
1个回答
0
投票

已解决。在read_ray函数中,这只是我的指针算法中的错误。感谢Mad Physicist提出的拆开整个结构的建议,这使我朝着正确的方向前进。

def read_ray(bytearr:bytearray,ray):
    ray_idx,num_seg = ray
    data = []
    assert num_seg==little_endian_int(bytearr[ray_idx:ray_idx+4])
    ray_idx = ray_idx + 4
    for seg_ptr in range(ray_idx,ray_idx + num_seg*208,208):
        ...
        data_integ = [bytearr[seg_ptr+offset:seg_ptr+offset+4] for offset in int_vars]            
        data_doubl = [bytearr[seg_ptr+offset:seg_ptr+offset+8] for offset in doubl_vars]
        ...
    return data
© www.soinside.com 2019 - 2024. All rights reserved.