🛠️Werkzeuge & Quellen

Alles aus dieser App lässt sich mit freien Werkzeugen nachprüfen. Die Beispielausgaben stammen aus echten Dateien mit den erfundenen Beispieldaten.

🔎Untersuchen

# Was ist das für eine Datei? (Ausgaben echt, Dateien mit Beispieldaten)
$ file umsatz.xls umsatz.xlsx umsatz.ods
umsatz.xls:  Composite Document File V2 Document, Little Endian, Os: Windows, …
umsatz.xlsx: Microsoft Excel 2007+
umsatz.ods:  OpenDocument Spreadsheet

# Die ersten 16 Byte
$ xxd -l 16 umsatz.xls
00000000: d0cf 11e0 a1b1 1ae1 0000 0000 0000 0000  ................
$ xxd -l 16 umsatz.xlsx
00000000: 504b 0304 1400 0808 0800 8e2e 3c5d 0000  PK..........<]..

# In das ZIP-Paket schauen und einen Teil ausgeben
$ unzip -l umsatz.xlsx
$ unzip -p umsatz.xlsx xl/worksheets/sheet1.xml | xmllint --format -

🔄Umwandeln mit LibreOffice

# Umwandeln ohne Oberfläche (LibreOffice)
$ libreoffice --headless --convert-to xlsx umsatz.xls
$ libreoffice --headless --convert-to xls  umsatz.xlsx      # Filter „MS Excel 97“ = BIFF8
$ libreoffice --headless --convert-to ods  umsatz.xlsx

# CSV mit Filteroptionen: Trennzeichen 59 (;), Textbegrenzer 34 ("), Zeichensatz 76 (UTF-8)
$ libreoffice --headless --convert-to 'csv:Text - txt - csv (StarCalc):59,34,76' umsatz.xlsx

# Auf dem Mac heißt das Programm soffice:
$ /Applications/LibreOffice.app/Contents/MacOS/soffice --headless --convert-to xlsx umsatz.xls
✅ Tipp
Bei parallelen Aufrufen jedem Prozess ein eigenes Profil geben: -env:UserInstallation=file:///tmp/lo-profil-1 – sonst blockieren sie sich gegenseitig.

🐍Python

# .xlsx/.xlsm lesen und schreiben: openpyxl
import openpyxl, datetime

wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Umsatz"
ws.append(["Artikel", "Preis", "Menge", "Summe"])
ws.append(["Käse", 4.99, 2, "=B2*C2"])      # Formel wird nur gespeichert, nicht berechnet
ws["A4"] = datetime.date(2024, 1, 1)        # landet als 45292 mit Datumsformat in der Datei
wb.save("umsatz.xlsx")

wb = openpyxl.load_workbook("umsatz.xlsx", data_only=True)  # data_only: gespeicherte Ergebnisse statt Formeln
print(wb["Umsatz"]["D2"].value)  # None, solange noch kein Excel/LibreOffice die Datei berechnet hat
# alte .xls (BIFF2–BIFF8) lesen: xlrd ≥ 2.0 kann NUR noch .xls
import xlrd
bk = xlrd.open_workbook("umsatz.xls")
sh = bk.sheet_by_index(0)
print(sh.name, sh.nrows, sh.ncols, bk.datemode)   # datemode = DATEMODE-Record (0 = 1900)
print(xlrd.xldate_as_datetime(45292, bk.datemode)) # 2024-01-01 00:00:00

# .xlsb lesen: pyxlsb
from pyxlsb import open_workbook
with open_workbook("umsatz.xlsb") as wb:
    with wb.get_sheet(1) as sheet:
        for row in sheet.rows():
            print([c.v for c in row])

# pandas wählt die Engine passend zur Endung
import pandas as pd
df = pd.read_excel("umsatz.xlsx")                 # openpyxl
df = pd.read_csv("umsatz.csv", sep=";", decimal=",", encoding="utf-8-sig")  # -sig entfernt die BOM

🕵️Makros prüfen mit olevba

# Makros untersuchen, ohne sie auszuführen (oletools)
$ pip install oletools
$ olevba umsatz.xls
FILE: umsatz.xls
Type: OLE
No VBA or XLM macros found.

$ olevba --decode verdaechtig.xlsm     # zeigt Quelltext + verdächtige Schlüsselwörter (AutoOpen, Shell …)
$ olevba -a verdaechtig.xlsm           # nur die Analyse-Tabelle

📚Quellen

Record-Nummern, Header-Felder und Beispielwerte wurden zusätzlich mit Dateien geprüft, die openpyxl und LibreOffice 25.2 erzeugt haben. Stand: September 2026.