2016-11-22 53 views
2

我有一个bin文件,该文件编码在需要访问并转换为csv文件的应用程序中。我已经给了文档,但不知道如何在Python中访问这个文件的内容。如何使用QDataStream在Python中打开bin文件

这里有一些细节有关的数据集是如何序列化

Datasets.bin是使用使用的版本QDataStream Qt的QDataStream系列化:: Qt_4_7序列化的DataSet类的列表。

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

下面是一个脚本,显示如何正确读取数据集格式。

但是,目前它不能正确读取所有数据。这是因为PyQt没有直接支持的QList<double>QVector<QPointF>模板类。在代码中,我使用了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

这有点奏效。它访问内容,并将一些信息附加到行列表中。虽然这些信息很稀少,但我可以看到没有文件本身的情况下它会如何困难。我已经将它包含在上面。我仍在深入研究这些代码,以更好地理解它。 –