2016-11-22 11 views
2

У меня есть файл bin, который был закодирован в приложении, которое мне нужно получить и преобразовать в файл csv. Мне дана документация, но я не уверен, как получить доступ к содержимому этого файла в Python.Как открыть файл bin в Python с помощью QDataStream

Вот некоторые подробности о том, как набор данных был сериализованная

Datasets.bin список классов DataSet сериализовать с помощью QDataStream сериализации в Qt с использованием версии QDataStream :: Qt_4_7.

The format of the datasets.bin file is: 

quint32 Magic Number 0x46474247 
quint32 Version  1 
quint32 DataSet Marker 0x44415441 
qint32  # of DataSets  n 
DataSet DataSet 1 
DataSet DataSet 2 
    . 
    . 
    . 
    . 
DataSet DataSet n 


The format of each DataSet is: 

quint32  Magic Number 0x53455455 
QString  Name 
quint32  Flags   Bit field (Set Table) 
QString  Id   [Optional] 
QColor  Color   [Optional] 
qint32   Units   [Optional] 
QStringList   Creator Ids  [Optional] 
bool   Hidden   [Optional] 
QList<double> Thresholds  [Optional] 
QString   Source   [Optional] 
qint32   Role   [Optional] 
QVector<QPointF> data points 

Я искал в к документации потока данных PyQt4, но я не могу найти какие-либо конкретные примеры. Любая помощь, указывающая на меня в правильном направлении, будет отличной.

+0

было бы проще всего использовать QDataStream, например, с привязками Qt Python? –

+0

https://dl.dropboxusercontent.com/u/28824868/datasets.bin вот ссылка на файл набора данных, если кто-то хочет его протестировать –

+0

@MichaelBawol. Я попытался прочитать этот файл с C++, и он не работает в первой записи «Source». Таким образом, либо формат является неполным/неправильным, либо файл поврежден. Откуда вы получаете файлы? У вас есть небольшой пример игрушки с известным набором ценностей? – ekhumoro

ответ

1

Ниже приведен скрипт, который показывает, как правильно прочитать формат набора данных.

Однако в настоящее время он фактически не может правильно прочитать все данные. Это связано с шаблонами классов QList<double> и QVector<QPointF>, для которых PyQt не имеет прямой поддержки. В коде я использовал readQVariantList вместо отсутствующих методов PyQt, которые необходимы для чтения этих типов.

UPDATE:

Я спросил об обработке произвольных шаблонных классов в списке рассылки PyQt, и в author of PyQt confirmed, что нет никакого способа сделать это. Таким образом, похоже, что единственный вариант - написать какой-то инструмент преобразования на C++.

UPDATE2:

Кажется, я говорил слишком рано, потому что я сейчас обнаружил работы вокруг. datastream format гораздо проще, чем я думал, и поэтому чтение произвольных шаблонных классов может быть сведено к простому алгоритму - в основном, читать длину как uint32, а затем перебирать по range и читать содержащиеся элементы один за другим в один list:

points = [] 
length = stream.readUInt32() 
for index in range(length): 
    point = QPoint() 
    stream >> point 
    points.append(point) 

Ниже приводится пересмотренный вариант сценария:

from PyQt4 import QtCore, QtGui 

FLAG_HASSOURCE = 0x0001 
FLAG_HASROLE = 0x0002 
FLAG_HASCOLOR = 0x0004 
FLAG_HASID = 0x0008 
FLAG_COMPRESS = 0x0010 
FLAG_HASTHRESHOLDS = 0x0020 
FLAG_HASUNITS = 0x0040 
FLAG_HASCREATORIDS = 0x0080 
FLAG_HASHIDDEN = 0x0100 
FLAG_HASMETADATA = 0x0200 

MAGIC_NUMBER = 0x46474247 
FILE_VERSION = 1 
DATASET_MARKER = 0x44415441 
DATASET_MAGIC = 0x53455455 

def read_data(path): 
    infile = QtCore.QFile(path) 
    if not infile.open(QtCore.QIODevice.ReadOnly): 
     raise IOError(infile.errorString()) 

    stream = QtCore.QDataStream(infile) 
    magic = stream.readUInt32() 
    if magic != MAGIC_NUMBER: 
     raise IOError('invalid magic number') 
    version = stream.readUInt32() 
    if version != FILE_VERSION: 
     raise IOError('invalid file version') 
    marker = stream.readUInt32() 
    if marker != DATASET_MARKER: 
     raise IOError('invalid dataset marker') 
    count = stream.readInt32() 
    if count < 1: 
     raise IOError('invalid dataset count') 

    stream.setVersion(QtCore.QDataStream.Qt_4_7) 

    rows = [] 
    while not stream.atEnd(): 
     row = [] 

     magic = stream.readUInt32() 
     if magic != DATASET_MAGIC: 
      raise IOError('invalid dataset magic number') 

     row.append(('Name', stream.readQString())) 

     flags = stream.readUInt32() 
     row.append(('Flags', flags)) 

     if flags & FLAG_HASID: 
      row.append(('ID', stream.readQString())) 
     if flags & FLAG_HASCOLOR: 
      color = QtGui.QColor() 
      stream >> color 
      row.append(('Color', color)) 
     if flags & FLAG_HASUNITS: 
      row.append(('Units', stream.readInt32())) 
     if flags & FLAG_HASCREATORIDS: 
      row.append(('Creators', stream.readQStringList())) 
     if flags & FLAG_HASHIDDEN: 
      row.append(('Hidden', stream.readBool())) 
     if flags & FLAG_HASTHRESHOLDS: 
      thresholds = [] 
      length = stream.readUInt32() 
      for index in range(length): 
       thresholds.append(stream.readDouble()) 
      row.append(('Thresholds', thresholds)) 
     if flags & FLAG_HASSOURCE: 
      row.append(('Source', stream.readQString())) 
     if flags & FLAG_HASROLE: 
      row.append(('Role', stream.readInt32())) 

     points = [] 
     length = stream.readUInt32() 
     for index in range(length): 
      point = QtCore.QPointF() 
      stream >> point 
      points.append(point) 
     row.append(('Points', points)) 
     rows.append(row) 

    infile.close() 

    return rows 

rows = read_data('datasets.bin') 

for index, row in enumerate(rows): 
    print('Row %s:' % index) 
    for key, data in row: 
     if isinstance(data, list) and len(data): 
      print(' %s = [%s ... ] (%s items)' % (
        key, repr(data[:3])[1:-1], len(data))) 
     else: 
      print(' %s = %s' % (key, data)) 
+0

«Не знаю, сможет ли он прочитать QList или QVector , потому что PyQt не может напрямую поддерживать классы шаблонов C++». - Я думаю, что это хороший вопрос сам по себе. – Trilarion

+0

Это несколько сработало. Он обратился к содержимому и добавил некоторую информацию в список строк. Хотя эта информация была скудной, я вижу, как это будет трудно без самого файла. Я включил его выше. Я все еще вникаю в этот код, чтобы понять его лучше. –