使用要读取的 numpy 保存二进制文件的最安全方法

Safest way to save binary file with numpy to be read

我需要使用 numpy 保存一些数组,以便稍后使用 Android Java APP 和另一个使用 numpy 的 python 应用程序读取。到目前为止,我一直在为 io 使用 numpy.ndarray.tofile 和 numpy.ndarray.fromfile,由于两者的简单性,我都非常喜欢它们。我编写和读取此类二进制数组的解决方案是:

def write_feature_bin_file(filepath, features_list):

if os.path.isfile(filepath):
    os.remove(filepath)

allfeatures = numpy.vstack(features_list)
header = [allfeatures.shape[0]]
try:
    header.append(allfeatures.shape[1])
except Exception as e:
    header.append(1)

if allfeatures.dtype.name == 'uint8':
    header.append(0)
else:
    header.append(5)

header = numpy.array(header, dtype=numpy.int32)

try:
    binf = open(filepath, 'a')
    header.tofile(binf)
    allfeatures.tofile(binf)
    binf.close()
except Exception as e:
    print "Unable to save file: ", filepath
    print e

return

def read_feature_bin_file(filepath):

try:
    binf = open(filepath, 'r')

    header = numpy.fromfile(f, count=3, dtype=numpy.int32)
    print header

    rows = header[0]
    cols = header[1]
    dt = header[2]


    if dt == 0:
        features = numpy.fromfile(f, dtype=numpy.uint8)
    else:
        features = numpy.fromfile(f, dtype=numpy.float32)

    features.resize(rows, cols)
    binf.close()

    return features

except Exception as e:

    print "Unable to read file: ", filepath
    print e
    return None

我在这里所做的只是简单地向输出文件写入一个小的 header,包含三个整数,描述行数、列数和数据类型,可以是 uint8 或 float32 ,然后将其余数据附加到文件中。读取时,我读取header的前三个元素来检查数组属性,然后相应地读取文件的剩余部分。问题是:我不知道这是否安全,尤其是关于将要读取此文件的系统的字节顺序。

对我来说确保此文件在任何系统中都能被正确读取的最佳方法是什么?我知道 numpy 有 "save" 和 "load" 函数,它们都以 .npz 或 .npy 格式保存,但我不知道如何将它们移植到我的 Android 申请

two main options.

1.始终以相同的字节顺序保存

您可以将字节顺序严格定义为文件格式规范的一部分,并相应地对程序文件的读取器和写入器进行定义。 例如,对于 Numpy,您可以将字节序指定为 dtype character code 的一部分:<f4 代表一个 little-endian 4 字节浮点数 (=float32) 和 >f4 一个 big-endian。为了始终以 little-endian 格式写入,写入例程可以包含如下内容:

if allfeatures.dtype.name == 'uint8':
    header.append(0)
else:
    allfeatures = allfeatures.astype('<f4', copy=False)
    header.append(5)

header = numpy.array(header, dtype='<i4')

2。在文件header中指定字节序

这是 Numpy .npy 格式在幕后实现的(它存储 ndarray.dtype.descr 返回的 dtype 字符代码)。 .npy 格式在 Numpy 中非常容易使用,但在 Java 应用程序中可能就不那么容易使用了。所以也许最简单但仍然可靠的解决方案是在 header 前面存储一个额外的标志。这样可以在从 header.

读取数组维度之前轻松确定字节序。

或者,从当前 header 中的第三个标志确定字节顺序也是有意义的,但是你必须更改 uint8 的标识符(零具有相同的表示两者都大到 little-endianness,所以不能使用)。它可以像这样编程:

def read_feature_bin_file(filepath):

    with open(filepath, 'rb') as binf:
        header = numpy.fromfile(binf, count=3, dtype='<i4')
        if header[2] not in [1, 5]:  # Check endianness
            header = header.view('>i4')

        rows, cols, dt = header
        dtype = 'u1' if dt==1 else header.dtype.byteorder + 'f4'
        features = numpy.fromfile(binf, dtype)

    features.shape = (rows, cols)
    return features