Speichern von Strings in HDF5 Dateien mit h5py

Im folgenden Beitrag zeige ich ein einfaches Beispiel wie das Speichern von Strings mittels h5py als Dataset in HDF5 Dateien funktioniert.

HDF5 Daten als wissenschaftliches Speichermedium

In einem meiner R&D Projekte in der Medizintechnik führen wir Schnelltests (z.B. Blutzucker oder COVID Antigen Tests) auf sogenannten Point-of-Care Geräten durch. Dabei sind die Geräte, die sich noch in der Entwicklung befinden, so eingestellt, dass sie ein DEBUG Log erzeugen. Dieses Log ist natürlich von essentieller Bedeutung für die daran beteiligten Wissenschaftler und muss für tausende von durchgeführten Tests verfügbar und mit wissenschaftlicher Analysesoftware auszuwerten sein. Zusätzlich entstehen Messdaten der verschiedenen Sensoren und ausserdem gibt es für jeden Test einen Satz von Metadaten. Ein ideales Werkzeug sind dafür Dateien im HDF5 Format. Für jeden Test ensteht also eine HDF5 Datei, die im R&D Fall auch das DEBUG Log enthält.

HDF5 Ökosystem

Um überhaupt HDF5 Dateien managen zu können, gibt es einige fertige Bibliotheken:

Mit der Python Bibliothek h5py erstellt man ganz einfach Dateien im HDF5 Format. Zusätzlich verwenden wir im Projekt einen HSDS Service, um die Dateien in der Cloud speichern zu können. Mit der h5pyd Bibliothek bringen wir dann alles zusammen, erstellen neue Dateien und legen diese im HSDS ab.

Strings in HDF5 Dateien speichern

Das vom Testgerät geschrieben DEBUG Log ist letztlich nichts anderes als eine Liste von Strings. Für jeden durchgeführten Test soll das entsprechende DEBUG Log in der HDF5 Datei gespeichert werden.

Das gesamte Log liegt bereits als String vor, der Test ist bereits abgeschlossen, und es wird nur noch die h5 Datei fertig gestellt.

Um Strings in einer h5 Datei zu speichern benutzen wir sogenannte Datasets. Die Liste der Log Zeilen weisen wir wie bei einem Dictionary mit dem Namen des Datasets zu (Zeile 25). Wichtig dabei ist, dass die einzelnen Strings der Logzeilen als utf-8 encodierte Bytes vorliegen (Zeile 24). Damit sind wir schon fertig und haben die Daten gespeichert.

# h5py version 2.9.0
import random
import string

from h5py import File


def create_log(n):
    """
    a simple method to create a log string with a few 'log lines'
    """
    s = ""
    for _ in range(n):
        s += "".join(
            random.choices(string.ascii_uppercase + string.digits, k=random.randint(10, 100))
        )
        s += "\n"
    return s


def run():
    local_file = File("test_data.h5", "w")
    log = create_log(10)
    log_array = [line.encode("utf-8") for line in log.splitlines()]
    local_file["Log"] = log_array

    with File("test_data.h5", mode="r") as fr:
        log_data = fr["Log"]
        print(f"log lines: {len(log_data)}")
        for line in log_data:
            print(line.decode())


if __name__ == "__main__":
    run()


Strings aus HDF5 lesen

Strings aus HDF5 Datasets lesen, ist genauso einfach. Wir öffnen die Datei im read-Modus (Zeile 27) und greifen über den Namen des Datasets (Zeile 28) auf die Daten zu. Da es sich um eine einfache Liste handelt, iterieren wir einfach über alle Elemente der Liste und erhalten so zweilenweise das gesamte Log. Die Python Strings decodieren wir wieder aus den Bytes ( Zeile 31).

Ab Version 3 kein encoding mehr nötig

Ab h5py Version 3.0 weisen wir die Log Zeilen als einfaches Array direkt zu. Das encoding der jeweiligen Zeilen entfällt. Die Bibliothek unterstützt nun Python utf-8 Strings direkt.

log = create_log(10)    
local_file["Log"] = log.splitlines()