====== Archiv — ZIP, TAR, RAR, ISO ======
Vier Units für Archiv- und Abbildformate, alle vollständig in Lyx umgesetzt. Externe Bibliotheken braucht keine davon; einzige Abhängigkeit ist ''std.zlib'' für die DEFLATE-Kompression in ''std.zip''.
→ [[lyx_-_programmiersprache:units|Standard Library]] · [[lyx_-_programmiersprache:units:gzip|std.gzip]] · [[lyx_-_programmiersprache:units:zlib|std.zlib]]
Alle Beispiele dieser Seite sind mit ''lyxc 1.0.21A'' übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben. Die erzeugten Archive wurden zusätzlich mit ''unzip'', ''tar'' und ''7z'' gegengelesen.
----
===== Die vier Units =====
^ Unit ^ Lesen ^ Schreiben ^ Kompression ^ Beschreibung ^
| [[lyx_-_programmiersprache:units:zip|std.zip]] | ja | ja | DEFLATE (automatisch) | ZIP nach PKWARE APPNOTE; bis 4096 Einträge, kein ZIP64, kein Passwort |
| [[lyx_-_programmiersprache:units:tar|std.tar]] | ja | ja | keine | POSIX ustar; für ''.tar.gz'' mit [[lyx_-_programmiersprache:units:gzip|std.gzip]] kombinieren |
| [[lyx_-_programmiersprache:units:rar|std.rar]] | **nur stored** | nein | keine | RAR5-Reader; komprimierte Einträge sind unsichtbar (proprietärer Algorithmus) |
| [[lyx_-_programmiersprache:units:iso|std.iso]] | ja | ja | keine | ISO 9660 Level 1; Reader läuft den ganzen Verzeichnisbaum ab, Writer erzeugt ein flaches Wurzelverzeichnis |
===== Welches Format wofür =====
^ Aufgabe ^ Empfehlung ^ Warum ^
| Dateien austauschen | ''std.zip'' | überall lesbar, komprimiert automatisch |
| Sicherung oder Auslieferungspaket | ''std.tar'' + ''std.gzip'' | Rechte und Pfade bleiben erhalten, Kompression getrennt wählbar |
| Viele kleine Dateien bündeln, Größe egal | ''std.tar'' | kein Kompressionsaufwand, einfachstes Format |
| Bootfähiges CD-, DVD- oder USB-Abbild | ''std.iso'' | einziges Format der vier mit Abbild-Charakter |
| Fremdes ISO-Abbild auslesen | ''std.iso'' | Reader kennt Unterverzeichnisse |
| Vorhandenes RAR-Archiv lesen | ''std.rar'' | nur wenn die Einträge //stored// sind — sonst gar nicht |
| RAR erzeugen | **geht nicht** | ''std.rar'' hat keinen Writer; ''std.zip'' nehmen |
----
===== Ein Muster für alle =====
Die vier Units teilen sich dieselbe Handle-Schnittstelle. Wer eine kennt, kennt alle:
Lesen Schreiben
Open(pfad) → Handle WriterNew() → Handle
Count(h) → Anzahl WriterAdd(h, name, daten, laenge)
Name(h, idx) → Zeiger WriterSave(h, pfad) → 0 = ok
Size(h, idx) → Bytes WriterFree(h)
Find(h, name) → Index oder -1
Read(h, idx, puffer, max) → Bytes
Close(h)
Die Präfixe sind ''Zip'', ''Tar'', ''Rar'' und ''Iso'' — ''ZipCount'', ''TarCount'', ''RarCount'', ''IsoCount''. Einzige Abweichung: ''std.zip'' nennt die Größenabfrage ''ZipUncompSize'' (nicht ''ZipSize''), weil im Archiv zusätzlich die komprimierte Größe steht. ''std.rar'' hat nur die linke Spalte.
import std.zip;
import std.tar;
import std.iso;
import std.alloc;
import std.string;
// Dasselbe Muster fuer alle drei Schreiber
fn main(): int64 {
var z: int64 := ZipWriterNew();
ZipWriterAdd(z, "README.txt"c, "Hallo aus Lyx!"c as int64, 14);
PrintLn(StrConcat("ZIP gespeichert, rc = ", IntToStr(ZipWriterSave(z, "/tmp/demo.zip"c))));
ZipWriterFree(z);
var t: int64 := TarWriterNew();
TarWriterAdd(t, "daten/log.txt"c, "Zeile 1\nZeile 2\n"c as int64, 16);
PrintLn(StrConcat("TAR gespeichert, rc = ", IntToStr(TarWriterSave(t, "/tmp/demo.tar"c))));
TarWriterFree(t);
var i: int64 := IsoWriterNew();
IsoWriterAdd(i, "README.TXT"c, "ISO 9660 aus Lyx"c as int64, 16);
PrintLn(StrConcat("ISO gespeichert, rc = ", IntToStr(IsoWriterSave(i, "/tmp/demo.iso"c))));
IsoWriterFree(i);
// Und wieder lesen - ebenfalls dasselbe Muster
var h: int64 := ZipOpen("/tmp/demo.zip"c);
var idx: int64 := ZipFind(h, "README.txt"c);
var buf: int64 := alloc(256);
var n: int64 := ZipRead(h, idx, buf, 256);
poke8(buf + n, 0);
PrintLn(StrConcat(StrConcat("ZIP Eintraege: ", IntToStr(ZipCount(h))), StrConcat(" README.txt = ", buf as pchar)));
ZipClose(h);
return 0;
}
ZIP gespeichert, rc = 0
TAR gespeichert, rc = 0
ISO gespeichert, rc = 0
ZIP Eintraege: 1 README.txt = Hallo aus Lyx!
Die drei Dateien sind mit den üblichen Werkzeugen lesbar:
$ unzip -l /tmp/demo.zip
14 2017-01-01 00:00 README.txt
$ tar -tf /tmp/demo.tar
daten/log.txt
$ 7z l /tmp/demo.iso
..... 16 16 README.TXT
----
===== Pfadangaben und Rückgabewerte =====
Zwei Stolperstellen, die sich durch alle vier Units ziehen:
* **''std.zip'' erwartet Pfade als Adresse** (''%%"datei.zip"c as int64%%''), ''std.tar'', ''std.rar'' und ''std.iso'' als ''pchar'' (''%%"datei.tar"c%%''). Der Unterschied stammt aus #1264 und ist an den Signaturen der Einzelseiten ablesbar.
* **''…WriterSave'' liefert ''0'' bei Erfolg** (der jeweilige ''…_ERR_OK''-Wert), ''…Open'' dagegen ''0'' im **Fehlerfall** und sonst ein Handle. Wer beide Rückgaben gleich behandelt, prüft eine davon falsch herum.
Ebenfalls für alle vier gleich:
* ''Name()'' liefert einen **internen** Zeiger — nie freigeben, nach ''Close()'' nicht mehr benutzen.
* ''Read()'' schreibt in einen Puffer, den der Aufrufer selbst anlegt, und **terminiert nicht**. Für die Textausgabe hinter den gelesenen Bytes selbst ein Nullbyte setzen.
* ''Find()'' vergleicht den **vollständigen** Namen einschließlich Verzeichnisanteil (''daten/log.txt''), nicht nur den Dateinamen.
* Das Archiv liegt beim Lesen vollständig im Speicher; streamenden Zugriff gibt es bei keiner der Units.
----
===== Grenzen im Überblick =====
^ ^ std.zip ^ std.tar ^ std.rar ^ std.iso ^
| Einträge | 4096 | 4096 | 4096 | 4096 |
| Namenslänge | Archivgrenze | **100 Byte** | 511 Byte | 8.3 vorgesehen |
| Verzeichnisse | im Namen | im Namen | im Namen (lesend) | **flach beim Schreiben** |
| Zeitstempel | fest 2017-01-01 | 0 (1970) | gelesen, nicht ausgewertet | Erstellzeit im Abbild |
| Kompression | DEFLATE ab 65 Byte | keine | keine | keine |
Drei dieser Grenzen führen zu **stillem** Verhalten und sind auf den Einzelseiten belegt:
* **TAR schneidet zu lange Pfade ab.** Ein 110 Zeichen langer Pfad wird ohne Fehlermeldung auf 100 Zeichen gekürzt — GNU tar liest anschließend den gekürzten Namen.
* **ISO normalisiert Namen.** ''EinLangerName.txt'' wird zu ''EINLANGERNAME.TXT'', und ''unterordner/a.txt'' zu ''UNTERORDNER_A.TXT'' — der Schrägstrich wird ersetzt, ein Unterverzeichnis entsteht nicht.
* **RAR verschweigt komprimierte Einträge.** ''RarCount'' zählt sie nicht mit; ein Archiv kann „leer" wirken, obwohl ''7z l'' Dateien anzeigt.
----
===== Und die Kompression? =====
''std.zip'' bringt DEFLATE selbst mit (über ''std.zlib'') und entscheidet je Eintrag: bis 64 Byte //stored//, darüber komprimiert. Die anderen drei Formate komprimieren nicht — dafür gibt es eigene Units:
^ Unit ^ Aufgabe ^
| [[lyx_-_programmiersprache:units:gzip|std.gzip]] | gzip-Ströme lesen und schreiben — die zweite Hälfte von ''.tar.gz'' |
| [[lyx_-_programmiersprache:units:zlib|std.zlib]] | DEFLATE/Inflate und die zlib-Hülle, dazu Adler-32 und CRC-32 |
----
**Weiterführend:** [[lyx_-_programmiersprache:units:zip|std.zip]] · [[lyx_-_programmiersprache:units:tar|std.tar]] · [[lyx_-_programmiersprache:units:rar|std.rar]] · [[lyx_-_programmiersprache:units:iso|std.iso]] · [[lyx_-_programmiersprache:guides:iso|Guide: ISO-Abbilder]]
Letzte Aktualisierung: 2026-08-13 — Schnellstart durch ein lauffähiges Programm ersetzt (die drei alten Ausschnitte waren nie übersetzt worden) und um den Gegenlesetest mit ''unzip''/''tar''/''7z'' ergänzt. Neu: Format-Wahl mit Begründung, Grenzen-Vergleich der vier Units, die drei still wirkenden Grenzen und der Hinweis auf die uneinheitliche Pfad-Übergabe. Die Seite [[lyx_-_programmiersprache:units:rar|std.rar]] ist neu angelegt — sie war hier verlinkt, existierte aber nicht.
Codebeispiele geprüft: gegen **lyxc 1.2.5C** übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die ''pub fn''-Signaturen in ''aurum/std'' gehalten, 0 Abweichungen).