2010-07-02 13 views
1

Je dois stocker un fichier binaire avec un en-tête de 12 octets composé de 4 champs. Ils sont à savoir: sSamples (entier de 4 octets), sSampPeriod (entier de 4 octets), sSampSize (entier de 2 octets) et enfin sParmKind (entier de 2 octets). J'utilise 'struct' pour mes variables dans les champs désirés. Maintenant que je les ai définis séparément, comment pourrais-je les fusionner tous pour stocker l'en-tête «12 octets»?Stockage des données 'struct' dans un fichier binaire

sSamples  = struct.pack('i', nSamples) # 4-bytes integer 
sSampPeriod  = struct.pack('i', nSampPeriod) # 4-bytes integer 
sSampSize  = struct.pack('H', nSampSize) # 2-bytes integer/unsigned short 
sParmKind  = struct.pack('H', 9) # 2-bytes integer/unsigned short 

En outre, j'ai un réseau de flotteurs npVect de dimensionnalité D (numpy.ndarray - float32). Comment pourrais-je stocker ce vecteur dans le même fichier binaire, mais après l'en-tête?

+3

Notez que vous pouvez regrouper plusieurs valeurs à la fois: struct.pack ('Hi', foo, bar). En outre, vous devez placer un '>' ou un '<' avant la chaîne de format, de sorte qu'il sera empaqueté et décompacté correctement sur les systèmes avec une endianness différente. –

Répondre

1

struct.pack retourne une chaîne, de sorte que vous pouvez combiner les champs simplement par concaténation de chaîne:

header = sSamples + sSampPeriod + sSampSize + sParmKind 
assert len(header) == 12 
+0

Salut jhcl, merci pour le conseil! Pour stocker l'en-tête dans le fichier binaire, c'est sth. comme: binfile = open ('myfile.dat', 'wb') binfile.write (en-tête) puis, comment pourrais-je attacher ma variable 'npVect' à 'binfile'? – Javier

+0

C'est exactement ce qu'il faut pour écrire la valeur dans le fichier. Je ne connais pas numpy, alors je vais laisser quelqu'un d'autre commenter cela. – jchl

2

Comme Cody Brocious a écrit, vous pouvez emballer votre tête entière à la fois:

header = struct.pack('<iiHH', nSamples, nSampPeriod, nSampSize, nParmKind) 

Il a également l'endianness mentionné, ce qui est important si vous voulez emballer vos données afin de les décompresser de manière fiable sur des machines avec des architectures différentes. Le < au début de ma chaîne de format spécifie "empaqueter ces données en utilisant une convention little-endian". En ce qui concerne le tableau, vous devrez en emballer la longueur afin de déterminer le nombre de valeurs à décompresser lorsque vous le relirez. Faire tout en un seul appel:

flattened = npVect.ravel() # get a 1-D array of numbers 
arrSize = len(flattened) 
# pack header, count of numbers, and numbers, all in one call 
packed = struct.pack('<iiHHi%df' % arrSize, 
    nSamples, nSampPeriod, nSampSize, nParmKind, arrSize, *flattened) 

Selon la taille de votre tableau est susceptible d'être, vous pourriez finir avec une chaîne énorme représentant le contenu de votre fichier binaire, et vous voudrez peut-être se pencher sur des solutions de rechange à struct qui ne nécessite pas que vous ayez le fichier entier en mémoire.

Déballer:

fmt = '<iiHHi' 
nSamples, nSampPeriod, nSampSize, nParmKind, arrSize = struct.unpack(fmt, packed) 
# Use unpack_from to start reading after the packed header and count 
flattened = struct.unpack_from('<%df' % arrSize, packed, struct.calcsize(fmt)) 
npVect = np.ndarray(flattened, dtype='float32').reshape(# your dimensions go here 
    ) 

EDIT: Oops, le format du tableau est pas tout à fait aussi simple que cela :) L'idée générale tient, cependant: aplatir votre tableau dans une liste de numéros en utilisant une méthode vous aimez, emballez le nombre de valeurs, puis emballez chaque valeur. De l'autre côté, lisez le tableau sous la forme d'une liste plate, puis appliquez la structure dont vous avez besoin.

EDIT: Modification des chaînes de format pour utiliser des spécificateurs de répétition plutôt qu'une multiplication de chaîne. Merci à John Machin de l'avoir signalé.

EDIT: Ajout du code numpy pour aplatir la matrice avant de l'emballer et de la reconstruire après le déballage.

+2

''

+0

+1 Bon point, j'avais oublié que vous pouviez mettre des nombres là-dedans. Si le tableau est vraiment * grand *, vous passerez encore beaucoup de paramètres à 'pack', grâce au tuple-unpacking du tableau, et vous aurez une énorme chaîne retournée. Les deux pointent vers trouver des alternatives à 'struct' si la performance souffre assez. – shambulator

+0

Salut les gars, je suivais le conseil de: arrSize = len (arr) packed = struct.pack (' Javier