2015-08-06 3 views
1

Мне нужно сохранить некоторые массивы с помощью numpy, чтобы позже их читать с помощью Android Java APP и другого приложения python с использованием numpy. До сих пор я использовал numpy.ndarray.tofile и numpy.ndarray.fromfile для io, оба из которых мне очень нравятся из-за простоты обоих. Мой гуманным для написания и чтения таких двоичных массивов были:Безопасный способ сохранения двоичного файла с numpy для чтения

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 

Что я делаю здесь просто написать небольшой заголовок в выходном файл, содержащий три целых числа, описывающее количество строк , количество столбцов и тип данных, которые могут быть либо uint8, либо float32, а затем добавление остальной части моих данных в файл. При чтении я читаю первые три элемента заголовка, чтобы проверить свойства массива, а затем прочитать оставшиеся файлы. Проблема в том, что я не знаю, насколько это безопасно, особенно в отношении сущности системы, которая будет читать этот файл.

Что было бы лучшим способом обеспечить, чтобы этот файл мог быть правильно прочитан в любой системе? Я знаю, что numpy имеет функции «сохранить» и «загрузить», как сохраненные в формате .npz, так и .npy, но я не знаю, как их перенести в мое приложение для Android.

+0

Хорошо попробуйте. Вы быстро узнаете, может ли ваше приложение Android правильно его прочитать. И что такое numpy? – greenapps

+0

Формат сортировки должен быть портативным. Документы находятся на https://docs.python.org/2/library/pickle.html и https://docs.python.org/3.1/library/pickle.html. –

ответ

2

Есть two main options.

1. Всегда сохранять с тем же байтов

Вы можете строго определить порядок байтов как часть спецификации формата файлов и чтения файлов программ и писателей соответственно. Например, с помощью Numpy вы можете указать endianness как часть dtype character code: <f4 представляет собой малонамеренное 4-байтовое число с плавающей запятой (= float32) и >f4 big-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. Укажите порядок следования байтов в заголовке файла

Это то, что Numpy .npy (он сохраняет код символа dtype, возвращаемый ndarray.dtype.descr). Формат .npy очень прост в использовании от Numpy, но, вероятно, не столько от приложения Java. Поэтому, возможно, самое простое, но все же твердое решение - сохранить дополнительный флаг перед заголовком. Таким образом, консистенция может быть легко определена до того, как размеры массива будут считаны из заголовка.

В качестве альтернативы было бы также иметь смысл определить сущность из третьего флага в вашем текущем заголовке, но тогда вам придется изменить идентификатор для uint8 (ноль имеет такое же представление как в больших, так и в малознакомых, поэтому нельзя использовать). Его можно запрограммировать следующим образом:

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 
+0

Спасибо! Мне особенно нравится кодирование этого на флагом форматирования заголовка, очень умное решение. –

Смежные вопросы