Transaktionssicherheit

nrg

Top Contributor
Hallo Zusammen,

z.B. wäre jetzt so eine Transaktion das Erstellen einer Ordnerstruktur, Schreiben einer Datei, Erstellen einer Signal-Datei und das Löschen einer Datei. Bei mir ist das meistens einfaches Exceptionhandling. Die Creates am Anfang gemerkt in einer Liste und am Ende der Delete - schlägt ein Schritt fehl kann ich im catch den Rollback machen. Das funktioniert auch ohne Probleme.

Jetzt wirds natürlich interessanter, wenn man mehrere schreibende bzw. modifizierende Transaktionsschritte hat. Mal ein ganz einfaches Beispiel: die Transaktion ist das Löschen von 2 Dateien. Schlägt der zweite Delete fehl, hat man natürlich beim Rollback schon ein Problem. Jetzt könnte man natürlich die Dateien erst umbenennen und danach löschen. Bisschen blöder wirds dann wieder bei Modifikationen. Klar, hier könnte man auch erst ein Backup erstellen.

Meine Frage ist eher, ob es Technologien gibt, die sowas "out-of-the-box" anbieten. Also eine Art try-catch-rollback-finally ;). Der Rollback ist im Grunde implizit auf alle durchgeführten Aktionen (file/db/whatever). Glaub aber fast, dass das wunschdenken ist :)
 

Bernd Hohmann

Top Contributor
Ich schlage mich mit Deinem Problem schon seit Jahren in verschiedenen Sprachen herum und bislang hat mir jedes Dateisystem (FAT, HPFS, NTFS, EXT2..4, ReiserFS ...) immer einen Strich durch die Rechnung gemacht.

In einem Projekt (wo ich keine "richtige" Datenbank nutzen kann) werden zb. ständig Userdaten aus einer kleinen Datei "user@domain.tld" gelesen, modifiziert, in eine "$$user@domain.tld$$" zurückgeschrieben, das Originalfile gelöscht und die Tmp-Datei in die Originaldatei umbenannt.

Dh. es liegt immer eine saubere Version der Datei herum (Originaldatei oder Temp-Datei, jeweils Grösse > 0)

Jetzt kommt es sporadisch zu irgendwelchen Hängern die selbst unter Linux nur mit hartem Reboot zu lösen sind. Ergebnis: die Originaldatei liegt mit 0 Bytes Grösse herum, von der Temp-Datei keine Spur. Von der Programmierung her darf dieser Zustand nicht vorkommen, passiert aber.

Dein Problem wäre ja noch halbwegs einfach abzuhandeln in dem man java.io.File nochmal als "nrg.io.File" schreibt wo alle del/ren Operationen in einer Queue landen und die Datei statt .delete() via .rename() nur temporär gelöscht wird.

Aber aufgrund meiner etwas schlechten Erfahrungen mit Dateisystemen habe ich etwas Zweifel dass das wirklich Transaktionssicher gestaltet werden kann.

Bernd
 

nrg

Top Contributor
ja, sehe jetzt auch nicht das problem darin, das in diesem speziellen fall zu handeln. wie du ja auch schon sagst, hat man im grunde 3 aktionen, delete, modify, create. die lassen sich alle ohne größere probleme mit rename und co. transaktionssicher gestalten. wenn natürlich mittendrin die vm abraucht, wars das mit der transaktion aber sowas trifft einen ja überall.

mir ging es eher um eine allgemeine möglichkeit. ehrlich gesagt kann ich mir das auch schwer in einer library oder einem framework vorstellen, sondern muss die programmiersprache an sich mitbringen. es geht ja im weiteren auch um objektzustände

edit: bzw. bei dateioperationen, wie du schon sagst, das dateisystem/os
 
Zuletzt bearbeitet:

Bernd Hohmann

Top Contributor
mir ging es eher um eine allgemeine möglichkeit. ehrlich gesagt kann ich mir das auch schwer in einer library oder einem framework vorstellen, sondern muss die programmiersprache an sich mitbringen. es geht ja im weiteren auch um objektzustände

Zustände sind das hier :)

Ich denke nicht, dass sowas in den Aufgabenbereich einer Programmiersprache fällt - es sei denn, sie heisst COBOL (oder eine andere Sprache die sich überwiegend um das herumschubsen von Records kümmert).

Aber eine Lib oder Framework... Vielleicht schreiben wir sowas einfach mal jetzt.

Bernd
 
T

tröööt

Gast
naja ... aber sind heutige daten-systeme nicht grundsätzlich journaled ?

Wiki/NTFS hat gesagt.:
Beim Speichern von Metadaten wird ein Journal geführt, das bedeutet, dass eine geplante Aktion zuerst in das Journal geschrieben wird. Dann wird der eigentliche Schreibzugriff auf die Daten ausgeführt und abschließend wird das Journal aktualisiert. Wenn ein Schreibzugriff nicht vollständig beendet wird, zum Beispiel wegen eines Absturzes, muss das Dateisystem nur die Änderungen im Journal zurücknehmen und befindet sich anschließend wieder in einem konsistenten Zustand.
sowie weiter unten
Wiki/NTFS hat gesagt.:
Erweiterungen seit Windows Vista [Bearbeiten]

Transactional NTFS (TxF) [Bearbeiten]

Mit der Einführung von Windows Vista wurde das NTFS-Dateisystem um das Konzept atomarer Operationen (Transaktionen) erweitert. Dieses transaktionsbasierte NTFS (engl. Transactional NTFS; kurz: TxF) ermöglicht es Anwendungen, Dateioperationen atomar auszuführen. Veränderungen am Dateisystem werden also nur dann ausgeführt, wenn die komplette Transaktion erfolgreich durchgeführt werden konnte. Zu einer Transaktion kann dabei eine Einzeloperation oder eine Abfolge von Dateioperationen gehören (beispielsweise das Erzeugen, Löschen oder Umbenennen einer oder mehrerer Dateien bzw. Verzeichnisse).

Transactional NTFS wurde auf Basis des ebenfalls mit Windows Vista eingeführten Kernel Transaction Manager[2] (KTM) implementiert, der Transaktionen auf der Ebene des Betriebssystemkerns ermöglicht. Es erweitert die bereits in vorigen NTFS-Versionen enthaltene Journal-Funktionalität, die sich auf die Integrität der Strukturen des Dateisystems beschränkt, um folgende Möglichkeiten:
Atomare Operationen auf Einzeldateien:
Ein Beispiel hierfür ist das Speichern einer Datei durch eine Anwendung: Kam es bislang während des Schreibvorgangs zu einem Programm- oder Rechnerabsturz, wurde unter früheren NTFS-Versionen nur ein Teil der Daten geschrieben, was zu einer unvollständigen Datei führen konnte. Dies war insbesondere problematisch, wenn eine frühere Dateiversion ersetzt bzw. überschrieben werden sollte – Datenverlust war die Folge.Atomare Operationen, die mehrere Dateien umfassen:
Wenn eine Applikation an mehreren Dateien zeitgleich Veränderungen durchführen muss, können allen notwendigen Dateioperationen in einer Transaktion zusammengefasst und eine Dateninkonsistenz im Falle eines Fehlers vermieden werden.Atomare Operationen über Rechnergrenzen hinweg:
Die Durchführung gleicher Operationen auf mehreren Rechnern ist eine übliche administrative Aufgabe; beispielsweise in einem Rechnerverbund eines Unternehmens. Transactional NTFS interagiert mit dem Distributed Transaction Coordinator (DTC), und stellt sicher, dass Änderungen erfolgreich auf allen beteiligten Rechnern, die Transactional NTFS unterstützen, durchgeführt werden konnten (z. B. die zentrale Synchronisation mehrerer Arbeitsplatzrechner).
Windows unterstützt Transaktionen ab Windows Vista bzw. Windows Server 2008.

außerdem zählt wikipedia in der liste der journaling-dateisysteme noch folgende auf

EXT3/4
HFS+
JFS
ReiserFS
XFS
ZFS

ich habe mir jetzt die einzelnen abschnitte zum journaling für die anderen FS jetzt nicht durchgelesen ... gehe aber von ähnlichem aus wie in der akutellen NTFS variante ...

ergo : die "transaktionssicherheit" von daten-ops sollte eigentlich im FS verankert und durch das OS bzw dessen kernel verwendet werden ...
 

Lumaraf

Bekanntes Mitglied
Dh. es liegt immer eine saubere Version der Datei herum (Originaldatei oder Temp-Datei, jeweils Grösse > 0)

Jetzt kommt es sporadisch zu irgendwelchen Hängern die selbst unter Linux nur mit hartem Reboot zu lösen sind. Ergebnis: die Originaldatei liegt mit 0 Bytes Grösse herum, von der Temp-Datei keine Spur. Von der Programmierung her darf dieser Zustand nicht vorkommen, passiert aber.

Das klingt für mich danach das da vor dem umbenennen noch ein Aufruf von FileDescriptor#sync() bzw FileChannel#force(boolean) fehlt.
 

Bernd Hohmann

Top Contributor
Das klingt für mich danach das da vor dem umbenennen noch ein Aufruf von FileDescriptor#sync() bzw FileChannel#force(boolean) fehlt.

Die Doku war etwas unklar dazu;: bezieht sich .sync() auf Filehandles innerhalb der aktuellen JVM oder auf das gesamte Dateisystem des OS?

Hatte das bei Einführung probiert und massive Performanceeinbrüche des gesamten Systems gehabt, danach nie wieder angefasst.

Da fällt mir unpassend ein, dass gerade dieses Projekt maximal gegen Java 1.2 (oder 1.4 - müsst ich nachsehen) kompiliert werden darf.

Bernd
 

nrg

Top Contributor
das journaling bietet dem os selbst die transaktionssicherheit beim schreiben einer datei, um eine datenkonsistenz zu gewährleisten. jetzt ist die frage, ob es einer programmiersprache bzw. auf lowlevel der maschinensprache möglich ist, das journaling asynchron darzustellen.
 
T

tröööt

Gast
Was hast Du Vollspaten-Hobbyadmin an "Ich schlage mich mit Deinem Problem schon seit Jahren in verschiedenen Sprachen herum und bislang hat mir jedes Dateisystem (FAT, HPFS, NTFS, EXT2..4, ReiserFS ...) immer einen Strich durch die Rechnung gemacht." nicht verstanden?

den fakt das es einfach mal alle modernen daten-systeme und OS anbieten und auch nutzen ...

wenn linux crashed während man auf platte schreibt stellt fschk nach nem crash den stand wieder her der erfolgreich abgeschlossen wurde bevor "write()" gecallt wird ... zumindest auf nem Ext4 unter OpenSuSE 12.x ...

warum es also mit java ... oder wie du sagst : anderen sprachen ... nicht funktioniert kann doch nur den schluss zu lassen das diese die vom OS genutzte fähigkeit das journaling zu nutzen eben nicht nutzen (können) ... warum auch immer ...

bevor du dich also mal wieder über jemanden auslässt der sich lustig drüber macht wie du dir selbst in deinen posts/threads immer mal wieder gerne widersprichst versuch es einfach mal zu verstehen ...


@nrg
tja ... man könnte mal gucken ob man was über NIO.2 File-API rausbekommt ob diese auf bestimmten OS mit passendem FS in der lage dazu ist das journaling auch zu nutzen ...
unter windows und NTFS dürfte das sicher schwer werden ... aber unter unix mit Ext4 sollte es definitiv machbar sein ...
wenn nich kann man ja mal versuchen den fs-treiber des kernels direkt anzuzapfen
 

Bleiglanz

Gesperrter Benutzer
Ich versteh ehrlich gesagt eure Diskussion nicht ganz, ein Unix
Code:
rm file
ist in etwa so wie das Abschiessen einer Rakete, ich kann mir nicht recht vorstellen wie man da von einer höheren Programmiersprache aus eine Transaktion mit Rollback drumherum basteln soll/kann.

Journaling auf OS-Ebene ist doch ganz was anderes, das ist doch Welten von der Java JTA entfernt. Eure Diskussion klingt fast so, als wolltet ihr einen Java-Transaktionsmanager für Operationen auf dem Dateisystem schreiben? Das ist wahrscheinlich SEHR schwierig - wenn nicht unlösbar.
 

KSG9|sebastian

Top Contributor
Zudem ist das Problem doch damit nicht gelöst:

TX: 2 Dateien schreiben 1 löschen 1 ändern

1. schreiben - ok
2. schreiben - ok
3. löschen - ok
4. ändern - fail

Wie soll durch Journaling jetzt bitte der alte Zustand wiederhergestellt werden? 1, 2 und 3 waren ja erfolgreich...
 

Bernd Hohmann

Top Contributor
Ich versteh ehrlich gesagt eure Diskussion nicht ganz, ein Unix
Code:
rm file
ist in etwa so wie das Abschiessen einer Rakete, ich kann mir nicht recht vorstellen wie man da von einer höheren Programmiersprache aus eine Transaktion mit Rollback drumherum basteln soll/kann.

In dem man den Abschuss der Rakete nur simuliert.

Ich bin da ganz bei nrg weil ich sein Problem auch immer mal wieder habe: man bearbeitet einen Satz Dateien und irgendwo ganz hinten klemmt es und man möchte alle Bearbeitungsschritte ungeschehen machen.

Vielleicht wäre "Snapshot" eine bessere Bezeichnung als Transaktion. Also alles, was man anfassen möche vorher beiseite kopieren, Änderungen machen und im Fehlerfall den Ursprungszustand restaurieren.

Singlethreaded kann ich mir das noch gut vorstellen (zb über ein eigenes File-Objekt), Multithreaded? Uhhh..... :reflect:

Bernd
 

Bernd Hohmann

Top Contributor
warum es also mit java ... oder wie du sagst : anderen sprachen ... nicht funktioniert kann doch nur den schluss zu lassen das diese die vom OS genutzte fähigkeit das journaling zu nutzen eben nicht nutzen (können) ... warum auch immer ...

Journaling ist fester Bestandteil des Dateisystems. Ich habe arge Zweifel daran, dass sich irgendjemand die Mühe gemacht hat, die Java-Runtime ausgerechnet am Journaling vorbei arbeiten zu lassen.

bevor du dich also mal wieder über jemanden auslässt der sich lustig drüber macht wie du dir selbst in deinen posts/threads immer mal wieder gerne widersprichst versuch es einfach mal zu verstehen ...

Du hast einen Knall, der ausreicht das Universum nochmal von der Singularität zur Unendlichkeit anzutreiben.
 

Bleiglanz

Gesperrter Benutzer
Na dann:

1) Bearbeite Datei1
2) Bearbeite Datei2
...
47) Bearbeite Datei47: FEHLER! HILFE

Probrammierer: WTF, ab ins Wochenende.
Chef: Nein, du machst das so

1) KOPIERE Datei1
1') Bearbeite KOPIE1
2) KOPIERE Datei2
2') Bearbeite KOPIE2
...
WENN ERFOLGREICH
1) Überschreibe Datei1 mit KOPIE1
2) Überschreibe Datei2 mit KOPIE2
...
47) Überschreibe Datei47 mit KOPIE 47: FEHLER Hilfe

..
kann man beliebig iterieren, da wird nie eine Transaktion im Sinne von ACID draus, das kann so nicht funktionieren. Man muss das in eine Datenbank schieben.
 

Bernd Hohmann

Top Contributor
kann man beliebig iterieren, da wird nie eine Transaktion im Sinne von ACID draus, das kann so nicht funktionieren. Man muss das in eine Datenbank schieben.

Das klingt jetzt aber so, als ob eine Datenbank ein mysteriöse Black-Box ist, die deus ex machina alle Probleme eines Dateisystems abgestreift hat. Wenn die Datenbank das schafft, müsste man es auch im Dateisysstem schaffen - oder irre ich hier?

Bernd
 

tfa

Top Contributor
Wenn die Datenbank das schafft, müsste man es auch im Dateisysstem schaffen - oder irre ich hier?
Sicherlich geht das. Ich hatte vor langer Zeit auch mal dieses Problem. Wenn ich mich recht erinnere, habe ich versucht, das so zu lösen:

1. Kopiere Datei -> Datei.work
2. Bearbeite Datei.work
3. Benenne Datei -> Datei.recover
4. Benenne Datei.work -> Datei
5. Lösche Datei.recover

Wenn der Prozess zwischen 1. und 4. stirbt, kann man beim Neustart "Datei.recover" wieder herstellen und "Datei.work" löschen, sozusagen einen Rollback machen. Zusammen mit den Zeitstempeln sollte das möglich sein.
 

Shadoka

Mitglied
Wenn ich die Lösung von tfa richtig verstanden habe, ist das im Prinzip ja ein optimistisches Sperrverfahren, wo man auf lokalen Kopien arbeitet und durch Validierung am Ende per Timestamp feststellt, ob alle Änderungen gemacht werden dürfen.
Diese Vorgehensweise dürfte wahrscheinlich funktionieren, aber es ist von Nutzungskontext abhängig, ob es sinnvoll ist.

Die Validierung lässt sich auch beliebig komplex gestalten, je nachdem ob Konsistenzbedingungen an diese oder jene Datei, Ordnerstruktur, o.ä. geknüpft sind.
 
E

Empire@Work

Gast
Wuie wäre es statt datei gefrikel zu machen das ganze sauber zu versionieren?

Erst die neu datei erstellen, dann validieren dass sie existiert mit inhalt, danach dann austauschen. (Btw kann es hier durch fehlerhafte schreibblockaden der hardware unabhängig was und wie immer mal probleme geben, da hilft dann auch kein anderes system mehr.)

Workaround?
Hardcore lösung, inner vm mit snapshoting fürs image machen. Solange der host stabil läuft, was eigentlich unter linux gegeben ist, kann die vm den nicht zum absturz bringen, somit kann man die vm ntfalls abschiessen, snapshot resetten und gut is.


Zudem sollte man jegliche art von schreibcaches auschalten wenn man sichergehen muss das datien geschreiben sind wenns das system returnt. (evtl extra platte dafür nehmen, dass nicht alles plötzlich extrem langsam wird)
 
T

tröööt

Gast
Zudem ist das Problem doch damit nicht gelöst:

TX: 2 Dateien schreiben 1 löschen 1 ändern

1. schreiben - ok
2. schreiben - ok
3. löschen - ok
4. ändern - fail

Wie soll durch Journaling jetzt bitte der alte Zustand wiederhergestellt werden? 1, 2 und 3 waren ja erfolgreich...

ind dem man bis zum ende von 4) alles im RAM oder in kopien macht und erst nach abschluss ALLER schritte wirklich daten auf platte schreibt ... und erst wenn hier alles wirklich fehlerfrei geschrieben wurde die sicherungsdaten entfernen ... DANN kann journaling schon helfen ... zumindest wenn der gesamte block als "eine" operation eingetragen wird
 

Ark

Top Contributor
Ich habe mir auch schon mal Gedanken zu dem Thema gemacht. Momentan bin ich bei folgendem Ansatz (gewählte Dateinamen dienen hier mehr der Illustration):

  1. Erzeuge atomar(!) eine neue(!) Datei
    Code:
    TRANSAKTION_LAEUFT
    . (Wenn das fehlschlägt, versucht gerade jemand anderes sich an einer Transaktion.)
  2. Wenn du eine Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    findest, schließe zunächst die vormals begonnene Transaktion sauber ab (siehe unten). Wenn du sie aber nicht vorfindest, mache die vormals begonnene Transaktion rückgängig (siehe unten).
  3. Erzeuge Dummy-Dateien so, dass klar ist, was passieren soll, und arbeite auf diesen Dateien, etwa
    Code:
    Name~
    für eine Datei, die nach Abschluss der Transaktion die Datei
    Code:
    Name
    ersetzt/erzeugt, oder
    Code:
    Name$
    als Hinweis dafür, dass die Datei
    Code:
    Name
    nach der Transaktion gelöscht sein wird. (Die Zuordnung zu den tatsächlichen Dateinamen muss natürlich eineindeutig sein, was die Wahl der Dateinamen für die "richtigen" Dateien einschränkt.)
  4. Synchronisiere alle Dateiinhalte bzw. Metadaten.
  5. Erzeuge atomar(!) eine neue(!) Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    .
  6. Schließe die Transaktion ab (siehe unten).
  7. Lösche atomar(!) die Datei
    Code:
    TRANSAKTION_LAEUFT
    .

Der eigentliche Abschluss der Transaktion sieht dabei wie folgt aus:
  1. Vorbedingung: Man muss gerade selbst die Datei
    Code:
    TRANSAKTION_LAEUFT
    wie oben beschrieben angelegt haben.
  2. Benenne jede Datei
    Code:
    Name~
    in
    Code:
    Name
    um und lösche für jede Datei
    Code:
    Name$
    die dazugehörige
    Code:
    Name
    , lösche danach alle
    Code:
    Name$
    .
  3. Synchronisiere alle Dateiinhalte bzw. Metadaten.
  4. Lösche atomar(!) die Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    .

Das Rückgängigmachen einer Transaktion sieht wie folgt aus:
  1. Vorbedingung: Man muss gerade selbst die Datei
    Code:
    TRANSAKTION_LAEUFT
    wie oben beschrieben angelegt haben.
  2. Lösche jede Datei
    Code:
    Name~
    und jede Datei
    Code:
    Name$
    .

Probleme meines Ansatzes:
  1. Nebenläufiges Lesen funktioniert nur insofern, als dass zwar nur "komplette" Dateien vorliegen, aber zwischendurch könnten Dateien gelöscht oder erzeugt worden sein.
  2. Wenn man "sicher" lesen will (also nur abgeschlossene Transaktionen vorfinden will), muss man selbst eine Transaktion starten, auch wenn man nichts verändert. Das erfordert, dass das Dateisystem beschreibbar sein muss bzw. man selbst Schreibrechte hat, obwohl man nur lesen will.
  3. Es ist viel Platz auf der Platte nötig und dauert lange.
  4. Es könnte noch eine Datei
    Code:
    TRANSAKTION_LAEUFT
    sowie Dummydateien wie
    Code:
    Name~
    oder
    Code:
    Name$
    herumspuken, obwohl wirklich kein Prozess eine Transaktion durchführen will.

Ich muss aber zugeben, dass ich das noch nie praktisch umgesetzt habe, insofern ist das alles mit Vorsicht zu genießen.

Ark
 

Ark

Top Contributor
[WR]Mein im letzten Beitrag beschreibenes Verfahren ist im Umgang mit zu löschenden Dateien grob fehlerhaft. Hier nun eine (hoffentlich) weniger problematische Version:[/WR]
  1. Erzeuge atomar(!) eine neue(!) Datei
    Code:
    TRANSAKTION_LAEUFT
    . (Wenn das fehlschlägt, versucht gerade jemand anderes sich an einer Transaktion.)
  2. Wenn du eine Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    findest, schließe zunächst die vormals begonnene Transaktion sauber ab (siehe unten). Wenn du sie aber nicht vorfindest, mache die vormals begonnene Transaktion rückgängig (siehe unten).
  3. Erzeuge Dummy-Dateien so, dass klar ist, was passieren soll, und arbeite auf diesen Dateien, etwa
    Code:
    Name~
    für eine Datei, die nach Abschluss der Transaktion die Datei
    Code:
    Name
    ersetzt/erzeugt. Benenne atomar(!) eine zu löschende Datei
    Code:
    Name
    in
    Code:
    Name$
    um. (Die Zuordnung zu den tatsächlichen Dateinamen muss natürlich eineindeutig sein, was die Wahl der Dateinamen für die "richtigen" Dateien einschränkt.)
  4. Synchronisiere alle Dateiinhalte bzw. Metadaten.
  5. Erzeuge atomar(!) eine neue(!) Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    .
  6. Schließe die Transaktion ab (siehe unten).
  7. Lösche atomar(!) die Datei
    Code:
    TRANSAKTION_LAEUFT
    .

Der eigentliche Abschluss der Transaktion sieht dabei wie folgt aus:
  1. Vorbedingung: Man muss gerade selbst die Datei
    Code:
    TRANSAKTION_LAEUFT
    wie oben beschrieben angelegt haben.
  2. Benenne jede Datei
    Code:
    Name~
    in
    Code:
    Name
    um und lösche jede Datei
    Code:
    Name$
    .
  3. Synchronisiere alle Dateiinhalte bzw. Metadaten.
  4. Lösche atomar(!) die Datei
    Code:
    TRANSAKTION_FAST_BEENDET
    .

Das Rückgängigmachen einer Transaktion sieht wie folgt aus:
  1. Vorbedingung: Man muss gerade selbst die Datei
    Code:
    TRANSAKTION_LAEUFT
    wie oben beschrieben angelegt haben.
  2. Lösche jede Datei
    Code:
    Name~
    und benenne atomar(!) jede Datei
    Code:
    Name$
    zu
    Code:
    Name
    um.

Die oben beschriebenen Probleme des Ansatzes bleiben natürlich bestehen.

Ark
 

Neue Themen


Oben