Essayez de travailler avec des données binaires en Python

J'ai eu l'opportunité de traiter les données binaires avec Python, mais comme j'avais touché aux données binaires pour la première fois et que j'avais dû enquêter sur diverses choses, j'aimerais les garder en mémoire!

Cette fois, nous avons traité les données du fichier d'extension "**. Sl2 **", nous allons donc écrire les données .sl2 à titre d'exemple!

À propos des données binaires

La structure de données des données binaires est déterminée par chaque format. Cette fois, j'avais affaire à un fichier appelé .sl2 que j'ai vu pour la première fois, mais dans ce cas, j'ai d'abord besoin de connaître "la structure du fichier .sl2" d'une manière ou d'une autre. Si vous ne le savez pas, vous ne pouvez pas le gérer!

Dans mon cas, je me suis référé à la page suivante, donc je vais expliquer en fonction de cette page de référence. (** En conséquence, cette page était fausse ... **) https://wiki.openstreetmap.org/wiki/SL2

entête

Il semble que la plupart des données binaires aient un en-tête. Il s'agit d'une valeur fixe dans les premiers octets et contient une description du format de données telle que des informations de version.

Dans ce cas, le tableau et l'explication suivants sont décrits dans la colonne "** Structure de base **" de la page de référence. Il semble qu'il existe plusieurs types dans le fichier .sl2, mais pour le moment, il semble que l'en-tête soit de 10 octets.

The files show up with a 10 byte header. First 2 bytes describe the format version (01=SLG, 02=SL2). Bytes 5,4 provide the block size. It varies depending on the sensor: 0x07b2 for HDI=Primary/Secondary+DSI and 0x0c80 for Sidescan). Seen values are image.png

Ordre des octets

Très grosso modo, il s'agit de l '«arrangement» et de l' «ordre d'arrangement» des données et définit l'ordre dans lequel les données sont stockées lorsqu'elles sont écrites en mémoire.

Pour autant que je sache, l'ordre des octets appartient le plus souvent à "Big Endian" ou "Little Endian", vous devez donc savoir lequel.

Dans ce cas, j'ai découvert que c'était un peu tolandien car il y a la description suivante dans la colonne "** Structure de base **" de la page de référence.

The file is a binary file with little endian format. Float values are stored as IEEE 754 floating-point "single format".

Bloc d'octets

Enfin, nous lirons les données après l'en-tête. Sur la page de référence, le type de données et la longueur de chaque bloc sont définis comme indiqué dans le tableau ci-dessous (extrait partiel).

image.png

Tout d'abord, regardez la colonne de description des données dans la colonne la plus à droite et sélectionnez les données que vous souhaitez extraire. Après avoir décidé des données à extraire, vérifiez le type de données (type de variable) et la valeur de décalage.

Le décalage est l'information de la position par rapport au point de référence et représente l'adresse des données. Puisqu'il y a 144 octets dans un ensemble de données cette fois, cela signifie que le nombre d'octets dans lesquels les données sont écrites est affiché.

This should close the 144 byte frame.

Module struct Python

J'ai beaucoup organisé sur les données binaires ci-dessus. Nous utilisons un module appelé ** struct ** pour gérer ces données binaires. Document officiel

À propos de l'ordre des octets

La documentation officielle contient le tableau suivant, qui définit les caractères qui représentent l'ordre des octets. image.png

À propos du format de données

Comme confirmé dans le chapitre [Byte Block](#Byte Block), chaque donnée a son propre type de données (type valable). Il est nécessaire de changer la méthode de traitement en fonction du type de données, mais dans struct, tant que vous passez les informations de type de données Après cela, on a l'impression qu'il fera tout ce qu'il faut pour s'adapter au moule.

Cependant, le format peut différer du document officiel, vous devez donc le lire en conséquence. Dans ce cas, ce sera comme suit.

short int → unsigned short(H)
int       → unsigned long(L)
byte(int) → unsigned char(B)

image.png

Lecture de données binaires

Il peut être lu en définissant l'option lors de l'ouverture du fichier sur rb (read binary).

with open(file_name, 'br') as f:
   data = f.read()

Interprétation des données binaires

Vous pouvez convertir les données binaires lues en utilisant la fonction struct.unpack_from (). Le format de base est struct.unpack_from (type de données, données, offset). Je connais déjà le type de données et l'offset, il ne me reste plus qu'à le spécifier!

Voici une vue d'ensemble. Cela semble plus long que ce à quoi je m'attendais, mais en gros, j'ajuste d'abord l'en-tête, puis je répète le travail de déballage en décalant le décalage du nombre d'éléments.

import sys
import struct

OLAR_EARTH_RADIUS = 6356752.3142
# PI = Math: : PI
MAX_UINT4 = 4294967295
FT2M = 1/3.2808399  # factor for feet to meter conversions
KN2KM = 1/1.852     # factor for knots to km conversions

args = sys.argv

if args[1] == '':
    print('Usage:  python sl2decoder.py your_file.sl2')

block_offset = 0

#Décaler d'en-tête de 10 octets
block_offset += 10   

# Datatypes:
# ===================================================================================================
# Type    Definition                                          Directive for Python's String#unpack
# ---------------------------------------------------------------------------------------------------
# byte 	  UInt8                                               B
# short   UInt16LE                                            H
# int 	  UInt32LE                                            L
# float   FloatLE (32 bits IEEE 754 floating point number)    f
# flags   UInt16LE                                            H
# ---------------------------------------------------------------------------------------------------

#Définir le décalage et le type de données pour chaque élément
block_def = {
    'blockSize'         : {'offset': 26, 'type': '<H'},
    #  'lastBlockSize': {'offset': 28, 'type': '<H'},
    'channel'           : {'offset': 30, 'type': '<H'},
    'packetSize'        : {'offset': 32, 'type': '<H'},
    'frameIndex'        : {'offset': 34, 'type': '<L'},
    'upperLimit'        : {'offset': 38, 'type': '<f'},
    'lowerLimit'        : {'offset': 42, 'type': '<f'},
    'frequency'         : {'offset': 51, 'type': '<B'},
    #  'time1': {'offset': 58, 'type': '<H'}          # unknown resolution, unknown epoche
    'waterDepthFt'      : {'offset': 62, 'type': '<f'},  # in feet
    'keelDepthFt'       : {'offset': 66, 'type': '<f'},  # in feet
    'speedGpsKnots'     : {'offset': 98, 'type': '<f'},  # in knots
    'temperature'       : {'offset': 102, 'type': '<f'}, # in °C
    'lowrance_longitude': {'offset': 106, 'type': '<L'}, # Lowrance encoding (easting)
    'lowrance_latitude' : {'offset': 110, 'type': '<L'}, # Lowrance encoding (northing)
    'speedWaterKnots'   : {'offset': 114, 'type': '<f'}, # from "water wheel sensor" if present, else GPS value(?)
    'courseOverGround'  : {'offset': 118, 'type': '<f'}, # ourseOverGround in radians
    'altitudeFt'        : {'offset': 122, 'type': '<f'}, # in feet
    'heading'           : {'offset': 126, 'type': '<f'}, # in radians
    'flags'             : {'offset': 130, 'type': '<H'},
    #  'time': {'offset': 138, 'type': '<H', 'len': 4}          # unknown resolution, unknown epoche
}

with open('%s_output_py.csv' % args[0], 'w') as f_raw:
    title = ','.join(['Channel', 'Frequency', 'UpperLimit[ft]', 'LowerLimit[ft]', 'Depth[ft]', 'WaterTemp[C]', 'WaterSpeed[kn]',
 'PositionX', 'PositionY', 'Speed[kn]', 'Track[rad]','Altitude[ft]', 'Heading[rad]']) + '\n'
    f_raw.write(title)

    alive_counter = 0

    with open(args[1], 'br') as f:
        data = f.read()
        sl2_file_size = len(data)

        while block_offset < sl2_file_size:
            h = {}
            if alive_counter % 100 == 0:
                print('%d done...' % round(100.0*block_offset/sl2_file_size))

            for k, v in block_def.items():
                t_offset = block_offset + v['offset']
                h[k] = struct.unpack_from(v['type'], data, t_offset)

            print(h['blockSize'])
            block_offset += h['blockSize'][0]

            #Combinez en une seule ligne de données
            csv_line = ','.join([str(h['channel'][0]), str(h['frequency'][0]), 
                                 str(h['upperLimit'][0]), str(h['lowerLimit'][0]), 
                                 str(h['waterDepthFt'][0]), str(h['temperature'][0]), 
                                 str(h['speedWaterKnots'][0]), str(h['lowrance_longitude'][0]), 
                                 str(h['lowrance_latitude'][0]), str(h['speedGpsKnots'][0]), 
                                 str(h['courseOverGround'][0]), str(h['altitudeFt'][0]), 
                                 str(h['heading'][0])]) + '\n'

            f_raw.write(csv_line)

print('Read up to block_offset %d' % block_offset)


Recommended Posts

Essayez de travailler avec des données binaires en Python
Exploitez LibreOffice avec Python
Gérer les sons en Python
Essayez de travailler avec Mongo en Python sur Mac
Travailler avec LibreOffice en Python: import
Travailler avec des images DICOM en Python
Essayez de gratter les données COVID-19 Tokyo avec Python
Obtenez des données supplémentaires vers LDAP avec python
Essayez de vous connecter à qiita avec Python
Gérez les structures de données 3D avec les pandas
Analyse de données avec python 2
Essayez de gratter avec Python.
Dichotomie avec Python
Essayez gRPC en Python
Dichotomie avec python
Dichotomie avec Python 3
Essayez 9 tranches en Python
Recherche binaire en Python
Analyse de données avec Python
Lire les données de la table dans un fichier PDF avec Python
Une histoire sur la gestion des données binaires en Python
[Introduction pour les débutants] Manipuler MySQL avec Python
Exemple de données créées avec python
Gérer les données ambiantes en Python
Grattage au sélénium en Python
Grattage avec chromedriver en python
Exemple de code spécifique pour travailler avec SQLite3 en Python
Afficher les données UTM-30LX en Python
Débogage avec pdb en Python
Essayez la sortie Python avec Haxe 3.2
Obtenez des données Youtube avec python
Essayez d'implémenter la mémoire associative par hop field network en Python
Python: travailler avec Firefox avec du sélénium
Essayez d'incorporer Python dans un programme C ++ avec pybind11
Grattage avec du sélénium en Python
Essayez LINE Notify avec Python
Recherche binaire en Python / C ++
Algorithme en Python (dichotomie)
Grattage avec Tor en Python
Tweet avec image en Python
Combiné avec ordinal en Python
Affichage des données d'informations de position en Python --Essayez de tracer avec la bibliothèque d'affichage de carte (folium) -
Essayez d'exécuter Python avec Try Jupyter
Implémentons Yuma dans Python 3
Essayez la reconnaissance faciale avec Python
Lire des données json avec python
Essayez d'exécuter python dans l'environnement Django créé avec pipenv
Essayez de trier vos propres objets avec des files d'attente prioritaires en Python
[Homologie] Comptez le nombre de trous dans les données avec Python
Obtenez des données LeapMotion en Python.
Reconnaissance des nombres dans les images avec Python
Ecrire une dichotomie en Python
Essayez de gratter avec Python + Beautiful Soup
Tester avec des nombres aléatoires en Python
GOTO en Python avec Sublime Text 3
Lire les données des tampons de protocole avec Python3
Obtenir des données de Quandl en Python
Enregistrez le fichier binaire en Python
Scraping avec Selenium en Python (Basic)
Analyse CSS avec cssutils en Python