DOS - Namensgebung

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Humax.

    DOS - Namensgebung

    Hallo ich brauche für mein Programm die Verzeichnis- / Dateinamen wie sie in DOS heißen würden. --> Maximal 8 Zeichen, keine Leerzeichen, keine Punkte.

    Meine erste Frage wäre, wo ich nachlesen kann, welche Zeichen in Windows Pfadangaben erlaubt sind, in Dos aber nicht...

    Ich habe zuerst versucht Verzeichnis / Dateinamen die länger als die 8 erlaubten Zeichen sind entsprechend zu kürzen.
    Aus "F:\Win\Verzeichnis" wird dann "F:\WIN\VERZEI~1"
    Aus "F:\Win\Mein Verzeichnis" wird dann "F:\WIN\MEINVE~1"

    Aber ich habe dann gemerkt, dass Windows wohl auch anders sortiert als DOS, denn in Windows habe ich folgende Verzeichnisse angelegt:
    "F:\Test\verzeich _1"
    "F:\Test\verzeich 07"
    "F:\Test\verzeich dem"
    "F:\Test\verzeich mal"
    "F:\Test\verzeichnis1"
    "F:\Test\verzeichnis2"

    In DOS werden die 6 Verzeichnisse dann wie erwartet so angezeigt:

    "VERZEI~1"
    "VERZEI~2"
    "VERZEI~3"
    "VERZEI~4"
    "VERZEI~5"
    "VERZEI~6"

    Allerdings ist "VERZEI~4" dann entsprechend "F:\Test\Verzeich _1". Ich vermute dass der Unterstrich in Windows Sortierung anders behandelt wird als in DOS -Sortierung.
    Hat jemand was für mich wo ich mich einlesen kann. Irgendwie finde ich nur dir Standardangaben wie maximal 8 Zeichen und so. Wahrscheinlich verwende ich unzutreffende Suchwörter...

    Vielleicht gibt es ja auch schon ein Tool / Code oder irgendwas, was mir meine Verzeichnisliste DOSkonform ausgibt
    Hallo @Humax

    Folgendes:

    In DOS werden Dateinamen und Verzeichnisse anders sortiert als in Windows.
    Der Unterstrich (_) wird als Sonderzeichen behandelt und sortiert vor Buchstaben.
    Dies könnte erklären, warum "VERZEI~4" in DOS anders angezeigt wird.


    learn.microsoft.com/de-de/windows/win32/fileio/naming-a-file

    Du könntest ggf eine kleine Funktion schreiben, die deine Verzeichnis-Namen nach DOS konvertiert.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Ich habe einige Zeit damit verbracht einen Pascal - Code zu konvertieren, das hat aber nicht so richtig geklappt...
    Und da ich auch nicht wirklich rausgefunden habe, nach welchen Kriterien DOS sortiert bin ich einen Umweg gegangen.
    Ich habe über 'cmd.exe' und 'DIR'- Befehl die Verzeichnisse und Dateien eingelesen. Mit 'DIR' liest sortiert er in der Reihenfolge wie ich sie brauche. Anhand der vorgegebenen Sortierung dann die Namen gekürzt.
    Passt jetzt.
    Hallo @Humax

    Ich habe mal etwas probiert. Vielleicht ist es das was du suchst.... :)

    Im Bild einmal die "DOS-Sortierung und die VB-Sortierung".

    Windows vs DOS Sortierung
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Text.RegularExpressions
    3. Public Class FrmMain
    4. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. ' Pfad des Verzeichnisses
    6. Dim path As String = "A:\Test"
    7. ' Verzeichnisse und Dateien einlesen
    8. Dim directories As String() = Directory.GetDirectories(path)
    9. Dim files As String() = Directory.GetFiles(path)
    10. ' Verzeichnisse und Dateien kombinieren
    11. Dim allEntries = directories.Concat(files).ToList()
    12. ' Sortiere Einträge nach DOS-Logik
    13. allEntries.Sort(Function(a, b) DosCompare(a, b))
    14. ' DOS-konforme Namen erzeugen
    15. Dim prefixCounts As New Dictionary(Of String, Integer)
    16. For Each entry As String In allEntries
    17. Dim name As String = entry.Substring(entry.LastIndexOf("\") + 1).ToUpperInvariant()
    18. ' DOS-kompatiblen Namen erstellen
    19. Dim dosName As String = GenerateShortName(name, prefixCounts)
    20. ' Ausgabe in ListBox
    21. ListBox1.Items.Add($"{entry} -> {dosName}")
    22. ' Konsolenausgabe
    23. Console.WriteLine($"{entry} -> {dosName}")
    24. Next
    25. End Sub
    26. ' DOS-Sortierlogik
    27. Private Function DosCompare(a As String, b As String) As Integer
    28. Dim isDirA As Boolean = Directory.Exists(a)
    29. Dim isDirB As Boolean = Directory.Exists(b)
    30. ' Verzeichnisse vor Dateien sortieren
    31. If isDirA AndAlso Not isDirB Then
    32. Return -1
    33. ElseIf Not isDirA AndAlso isDirB Then
    34. Return 1
    35. End If
    36. ' ASCII-basierte Sortierung
    37. Dim nameA As String = a.Substring(a.LastIndexOf("\") + 1).ToUpperInvariant()
    38. Dim nameB As String = b.Substring(b.LastIndexOf("\") + 1).ToUpperInvariant()
    39. Return String.Compare(nameA, nameB, StringComparison.OrdinalIgnoreCase)
    40. End Function
    41. ' DOS-kompatiblen Namen erstellen
    42. Private Function GenerateShortName(name As String, ByRef prefixCounts As Dictionary(Of String, Integer)) As String
    43. ' Entferne unzulässige Zeichen und kürze den Namen auf 8 Zeichen
    44. Dim validName As String = Regex.Replace(name, "[^A-Z0-9]", "").ToUpperInvariant()
    45. If validName.Length > 8 Then validName = validName.Substring(0, 8)
    46. ' Suffix "~n" hinzufügen
    47. If Not prefixCounts.ContainsKey(validName) Then
    48. prefixCounts(validName) = 1
    49. Else
    50. prefixCounts(validName) += 1
    51. End If
    52. Return $"{validName}~{prefixCounts(validName)}"
    53. End Function
    54. End Class

    Bilder
    • winVSdos.jpg

      316,2 kB, 909×501, 33 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Es gibt doch entsprechende APIs dafür. GetShortPathName gibt Dir den 8.3 DOS Namen von einem Ordner/Datei (LongPath) zurück. GetLongPathName ist der umgekehrte Weg. Mit SetFileShortName kann man entsprechend einen 8.3 DOS Namen in einem LongPath hinterlegen/ändern.
    Mfg -Franky-
    GetShortPathName hat keine zuverlässigen Ergebnisse geliefert! Deshalb musste es ja was anderes sein. Ich habe Code auch aus Programmen die ebenfalls die 8.3 Namen benötigen probiert, zum Beispiel von Dfend Reloaded. Aber auch das hat nicht zu 100% richtigen Ergebnis geführt.

    @Amelie das sieht vielversprechend ( und aufgeräumter als mein Code...) aus, das werde ich mir Mal Zuhause genauer ansehen.

    -Franky- schrieb:

    Es gibt doch entsprechende APIs dafür. GetShortPathName gibt Dir den 8.3 DOS Namen von einem Ordner/Datei (LongPath) zurück. GetLongPathName ist der umgekehrte Weg. Mit SetFileShortName kann man entsprechend einen 8.3 DOS Namen in einem LongPath hinterlegen/ändern.


    Ich habe jetzt einige Beispiele probiert, keine funktioniert bei mir mit dem GetShortPathName. Hast du da ein funktionierendes Beispiel?
    Unter anderem habe ich mich hieran und hieran probiert. Beides funktioniert nicht. Und ich glaube selbst wenn der kurze 8.3 DOS Name zurückgegeben werden würde, wäre es für mein Programm nicht hilfreich, da ja nur dieser eine Pfad gekürzt wird ohne zu prüfen ob dieser Pfad (nach der Kürzung) nochmals existiert, sodass dann ~2 oder ~3 etc. draus wird...

    @Amelie ich denke spätestens komme ich du deinem Code...
    So nach einigem rumprobieren habe ich nun rausgefunden, das die API "GetShortPathName" doch funktioniert, wenn man 2 Dinge berücksichtigt.
    Zum Einen muss der Pfad der gekürzt werden soll auch existieren - soweit so klar... Zum Anderen - und das wusste ich nicht und dachte da ich immer, wenn ich meine eigenen Pfade kürzen wollte, das die API nicht funktioniert - muss der Pfad zwingend auf Laufwerk C existieren.
    Wenn ich also den Pfad 'C:\Programme' kürze dann funktioniert die API, wenn ich 'D:\Programme' kürze dann nicht.

    Ein kleines Problem besteht allerdings noch, denn die Pfade unter Windows NT Versionen werden unter bestimmten Voraussetzungen anders gekürzt als unter Windows 95 / 98 / DOS:
    Beispielsweise, wenn mindestens 4 Dateien oder Ordner mit der gleichen Erweiterung und den ersten 6 Zeichen in ihren Kurznamen existieren, dann wird der Name auf 2 Zeichen gekürzt und ein Hash benutzt, unter DOS ist das anders, da geht es mit 6 Zeichen (bzw. weniger, wenn noch mehr Dateien / Ordner bestehen) gefolgt von der Tilde und einer Zahl weiter.
    Wird hier ganz gut dokumentiert.

    Hier mal ein der kürzeste Code zum Abruf der Kurznamen mit API:

    VB.NET-Quellcode

    1. Declare Auto Function GetShortPathName Lib "kernel32.dll" (ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As Integer) As Integer
    2. Private Function GetShortDOSNameWINAPI(ByVal Pfad As String) As String
    3. Dim sb As New StringBuilder(256)
    4. GetShortPathName(Pfad, sb, sb.Capacity)
    5. If sb.ToString = String.Empty Then
    6. Return Path.GetFileName(Pfad)
    7. Else
    8. Pfad = sb.ToString.Replace(DOSCreatePath & "\", "")
    9. Return Pfad
    10. End If
    11. End Function


    Ich nutze jetzt also die API, werde mich aber nochmal mit dem Code von @Amelie für die Ausnahmen beschäftigen.
    Nochmal ein Update, falls das für jemand wichtig / interessant ist:
    Die 8.3 Namen können auch auf anderen Laufwerken aktiviert werden. Der Befehl um beispielsweise die Kurznamen auf allen Laufwerken zu aktivieren ist folgender:

    Quellcode

    1. fsutil 8dot3name set 0


    Allerdings wirkt sich das nur auf neu erstellte Verzeichnisse / Dateien aus... Also nicht praktikabel, da alle Verzeichnisse / Dateien neu erstellt werden müssten. Und selbst wenn man das macht oder die Kurznamen manuell vergibt , werden die Kurznamen in Zukunft nicht angepasst sollte man ein neues Verzeichnis erstellen, wodurch sich der Präfix möglicherweise ändern würde...

    Quellcode

    1. fsutil file setshortname


    Wenn ich wie bisher einfach den Pfad (ohne Dateien) auf Laufwerk C: erstelle, würden durch die WINApi, aufgrund fehlender Verzeichnisstruktur, ebenfalls falsche Ergebnisse geliefert. Somit müsste die komplette Verzeichnisstruktur auf C: abgebildet werden, damit der richtige Präfix generiert wird. Aber auch hier ist kein richtiges Ergebnis für DOS garantiert, da wie bereits erwähnt; unter WinNT Versionen Pfade max. bis ~4 in DOS-Namensgebung erstellt werden.
    Also ist auch das nicht wirklich praktikabel, zumal es auch nicht immer den richtigen Kurznamen für DOS ermittelt!

    Deshalb habe ich jetzt den Code von @Amelie etwas für meine Zwecke angepasst habe. Das funktioniert grundsätzlich, aber auch hier besteht noch 1 Problem:

    Ich kann mir leider nicht erklären, wie unter DOS in bestimmten Fällen der Präfix generiert wird.
    Hier ein Beispiel meiner Verzeichnisstruktur und was daraus logischerweise in Kurznamen raus kommen sollte und was in DOS passiert:

    Originalpfad________AlternativPfad

    KurznameDOSname
    F:\Test2\ve rzF:\Test2\v erz

    F:\Test2\verz~1F:\Test2\verz~1
    F:\Test2\ve rz ei


    F:\Test2\verzei~1F:\Test2\verzei~2
    F:\Test2\verzeich nis


    F:\Test2\verzei~2F:\Test2\verzei~3

    Wie man in der obigen Tabelle sieht, beginnt der Präfix von "VERZEI" bei ~2 anstatt bei ~1.
    Im Gegensatz dazu beginnt in der folgende Tabelle der Präfix richtigerweise bei ~1, wenn ich den Originalpfad "F:\Test2\ve rz" ändere, und das obwohl das entsprechende Verzeichnis in DOS jedes mal "VERZ~1" heißt und der Präfix von "VERZEI" dann eigentlich auch bei ~1 losgehen sollte!


    Originalpfad
    Kurzname
    DOSname
    F:\Test2\ver z
    F:\Test2\verz~1
    F:\Test2\verz~1
    F:\Test2\ve rz ei
    F:\Test2\verzei~1
    F:\Test2\verzei~1
    F:\Test2\verzeich nis
    F:\Test2\verzei~2
    F:\Test2\verzei~2



    Was mir nach bissl rumprobieren auffällt:
    Wenn das Verzeichnis "F:\Test2\ver z" in der Win-Sortierung an 1. Stelle steht, dann beginnt der Präfix bei "VERZEI" falsch mit ~2.
    Ist das Verzeichnis "F:\Test2\v erz" an 1. Stelle in der Win-Sortierung, dann stimmt der Präfix. Aber das immer korrekt zu ermitteln scheint mir zu schwer / zu viel Aufwand. ODER HAT DA JEMAND DIE PASSENDE IDEE

    Wenn also nicht jemand hier das entscheidende Wissen über die DOS-Namensgebung einbringen kann, gehe ich den einfachen Weg. Der User muss es richten. Dazu hat er 3 verschiedene Möglichkeiten:
    1.) Den kompletten Pfad zur auszuführenden Datei angeben. --> Wenn also die Datei: "F:\Jagged Alliance\Jagged Alliance - Deadly Games\dg.exe" gestartet werden soll, muss er als Pfad "F:\Jagged Alliance\Jagged Alliance - Deadly Games" angeben, anders würde es reichen er würde "F:\" angegeben. Was in manchen Fällen sinnvoll sein kann!.
    2.) Korrekte DOS-Namensgebung beachten. Das heißt er korrigiert seine Verzeichnisstruktur für seine DOS-Programme entsprechend der 8.3 Namensregelung
    3.) Hoffen, das seine Namensgebung "entschlüsselt" werden kann und nicht falsch vom Programm generiert wird. In diesem Falle könnte er immer noch Möglichkeit 1 oder 2 nutzen.