Welke tekens zijn verboden in Windows- en Linux-directorynamen?

Ik weet dat /illegaal is in Linux, en de volgende zijn illegaal in Windows
(denk ik) *."/\[]:;|,

Wat mis ik nog meer?

Ik heb echter een uitgebreide gids nodig, en een die rekening houdt met
dubbelbyte tekens. Linken naar externe bronnen vind ik prima.

Ik moet eerst een map op het bestandssysteem maken met een naam die kan
verboden tekens bevatten, dus ik ben van plan die tekens te vervangen door
onderstreept. Ik moet dan deze map en de inhoud ervan naar een zipbestand schrijven
(met Java), dus elk aanvullend advies over de namen van zip-directories
zou op prijs worden gesteld.


Antwoord 1, autoriteit 100%

Een “uitgebreide gids” van verboden bestandsnaamtekens zal niet werken op Windows omdat het zowel bestandsnamen als tekens reserveert. Ja, karakters zoals
*"?en andere zijn verboden, maar er is een oneindig aantal namen die alleen bestaan uit geldige tekens die verboden zijn. Bijvoorbeeld spaties en punten zijn geldige bestandsnaamtekens, maar namen die alleen uit die tekens bestaan, zijn verboden.

Windows maakt geen onderscheid tussen hoofdletters en kleine letters, dus u kunt geen map maken met de naam Aals er al een map met de naam Abestaat. Erger nog, schijnbaar toegestane namen zoals PRNen CON, en vele andere, zijn gereserveerd en niet toegestaan. Windows heeft ook verschillende lengtebeperkingen; een bestandsnaam die geldig is in een map kan ongeldig worden als deze naar een andere map wordt verplaatst. De regels voor
bestanden en mappen een naam geven
staan in de Microsoft-documenten.

U kunt in het algemeen geen door gebruikers gegenereerde tekst gebruiken om Windows-directorynamen te maken. Als je wilt dat gebruikers alles kunnen noemen wat ze willen, moet je veilige namen maken zoals A, AB, A2et al., store door gebruikers gegenereerde namen en hun padequivalenten in een applicatiegegevensbestand, en voer padtoewijzing uit in uw applicatie.

Als u absoluut door gebruikers gegenereerde mapnamen moet toestaan, is de enige manier om te weten of ze ongeldig zijn, uitzonderingen op te vangen en aan te nemen dat de naam ongeldig is. Zelfs dat brengt gevaren met zich mee, aangezien de uitzonderingen voor geweigerde toegang, offline schijven en onvoldoende schijfruimte elkaar overlappen met de uitzonderingen die kunnen worden gegenereerd voor ongeldige namen. Je opent een enorm blikje pijn.


Antwoord 2, autoriteit 96%

Laten we het simpel houden en eerst de vraag beantwoorden.

  1. De verboden afdrukbare ASCII-tekenszijn:

    • Linux/Unix:

       / (forward slash)
      
    • Windows:

       < (less than)
        > (greater than)
        : (colon - sometimes works, but is actually NTFS Alternate Data Streams)
        " (double quote)
        / (forward slash)
        \ (backslash)
        | (vertical bar or pipe)
        ? (question mark)
        * (asterisk)
      
  2. Niet-afdrukbare tekens

    Als uw gegevens afkomstig zijn van een bron die niet-afdrukbare tekens zou toestaan, moet u op meer controleren.

    • Linux/Unix:

       0 (NULL byte)
      
    • Windows:

       0-31 (ASCII control characters)
      

    OPMERKING: Hoewel het legaal is onder Linux / UNIX-bestandssystemen om bestanden te maken met bedieningstekens in de bestandsnaam, Het is misschien een nachtmerrie voor de gebruikers om met dergelijke bestanden te handelen .

  3. Gereserveerde bestandsnamen

    De volgende bestandsnamen zijn gereserveerd:

    • Windows:

       CON, PRN, AUX, NUL 
        COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
        LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
      

      (zowel zelfstandig als met arbitraire bestandsextensies, b.v. LPT1.txt).

  4. Andere regels


3, Autoriteit 33%

Onder Linux en andere Unix-gerelateerde systemen zijn er slechts twee tekens die niet in de naam van een bestand of map kunnen verschijnen, en dat zijn NUL '\0'EN SLASH '/'. De schuine streep kan natuurlijk verschijnen in een padnaam, scheidingsdirectory-componenten.

Gerucht1gaat dat Steven Bourne (van ‘shell’-faam) een map had met 254 bestanden, één voor elke letter (tekencode) die in een bestandsnaam kan voorkomen (met uitzondering van /, '\0'; de naam .was natuurlijk de huidige directory). Het werd gebruikt om de Bourne-shell te testen en veroorzaakte routinematig schade aan onoplettende programma’s zoals back-upprogramma’s.

Andere mensen hebben de Windows-regels behandeld.

Merk op dat MacOS X een hoofdletterongevoelig bestandssysteem heeft.


1Het was Kernighan & Pike in The Practice of Programmingdie hetzelfde zei in hoofdstuk 6, Testen, §6.5 Stresstests:

Toen Steve Bourne zijn Unix-shell aan het schrijven was (die bekend werd als de Bourne-shell), maakte hij een directory van 254 bestanden met namen van één teken, één voor elke bytewaarde behalve '\0'en slash, de twee tekens die niet in Unix-bestandsnamen mogen voorkomen. Hij gebruikte die map voor allerlei tests van patroonovereenkomst en tokenisatie. (De testdirectory is natuurlijk gemaakt door een programma.) Jaren daarna was die directory de vloek van programma’s die door bestandsbomen lopen; het testte hen tot vernietiging.

Merk op dat de directory vermeldingen .en ..moet bevatten, dus het waren aantoonbaar 253 bestanden (en 2 mappen), of 255 naamitems, in plaats van 254 bestanden. Dit heeft geen invloed op de effectiviteit van de anekdote, of het zorgvuldige testen dat het beschrijft.


4, Autoriteit 15%

De gemakkelijke manier om Windows het antwoord te laten vertellen, is door te proberen een bestand te hernoemen via Verkenner en / in te typen voor de nieuwe naam. Windows zal een berichtvenster openen met de lijst met illegale tekens.

A filename cannot contain any of the following characters:
    \ / : * ? " < > | 

https://support.microsoft.com/en-us/kb/177506


Antwoord 5, autoriteit 12%

Nou, al was het maar voor onderzoeksdoeleinden, dan kun je het beste kijken naar dit Wikipedia-artikel op Bestandsnamen.

Als je een draagbare functie wilt schrijven om gebruikersinvoer te valideren en op basis daarvan bestandsnamen te maken, is het korte antwoord niet doen. Bekijk een draagbare module zoals Perl’s File::Specom een glimp op te vangen van iedereen de hop die nodig is om zo’n “eenvoudige” taak te volbrengen.


Antwoord 6, autoriteit 3%

Voor Windows kunt u dit controleren met PowerShell

$PathInvalidChars = [System.IO.Path]::GetInvalidPathChars() #36 chars

Om UTF-8-codes weer te geven die u kunt converteren

$enc = [system.Text.Encoding]::UTF8
$PathInvalidChars | foreach { $enc.GetBytes($_) }
$FileNameInvalidChars = [System.IO.Path]::GetInvalidFileNameChars() #41 chars
$FileOnlyInvalidChars = @(':', '*', '?', '\', '/') #5 chars - as a difference

Antwoord 7, autoriteit 2%

Voor iedereen die op zoek is naar een regex:

const BLACKLIST = /[<>:"\/\\|?*]/g;

Antwoord 8, autoriteit 2%

In Windows 10 (2019) zijn de volgende tekens verboden door een fout wanneer u ze probeert te typen:

Een bestandsnaam mag geen van de volgende tekens bevatten:

\ / : * ? " < > |


Antwoord 9

Hoewel de enige illegale Unix-tekens /en NULLkunnen zijn, moet er rekening worden gehouden met de interpretatie van de opdrachtregel.

Hoewel het bijvoorbeeld legaal is om een bestand 1>&2of 2>&1in Unix te noemen, kunnen bestandsnamen zoals deze verkeerd geïnterpreteerd bij gebruik op een opdrachtregel.

Het is misschien ook mogelijk om een bestand $PATHte noemen, maar als je het probeert te openen vanaf de opdrachtregel, zal de shell $PATHvertalen naar zijn variabele waarde .


Antwoord 10

Hier is een c#-implementatie voor Windows gebaseerd op Christopher Oezbek’s antwoord

Het is ingewikkelder gemaakt door de boolean-map containFolder, maar dekt hopelijk alles

/// <summary>
/// This will replace invalid chars with underscores, there are also some reserved words that it adds underscore to
/// </summary>
/// <remarks>
/// https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
/// </remarks>
/// <param name="containsFolder">Pass in true if filename represents a folder\file (passing true will allow slash)</param>
public static string EscapeFilename_Windows(string filename, bool containsFolder = false)
{
    StringBuilder builder = new StringBuilder(filename.Length + 12);
    int index = 0;
    // Allow colon if it's part of the drive letter
    if (containsFolder)
    {
        Match match = Regex.Match(filename, @"^\s*[A-Z]:\\", RegexOptions.IgnoreCase);
        if (match.Success)
        {
            builder.Append(match.Value);
            index = match.Length;
        }
    }
    // Character substitutions
    for (int cntr = index; cntr < filename.Length; cntr++)
    {
        char c = filename[cntr];
        switch (c)
        {
            case '\u0000':
            case '\u0001':
            case '\u0002':
            case '\u0003':
            case '\u0004':
            case '\u0005':
            case '\u0006':
            case '\u0007':
            case '\u0008':
            case '\u0009':
            case '\u000A':
            case '\u000B':
            case '\u000C':
            case '\u000D':
            case '\u000E':
            case '\u000F':
            case '\u0010':
            case '\u0011':
            case '\u0012':
            case '\u0013':
            case '\u0014':
            case '\u0015':
            case '\u0016':
            case '\u0017':
            case '\u0018':
            case '\u0019':
            case '\u001A':
            case '\u001B':
            case '\u001C':
            case '\u001D':
            case '\u001E':
            case '\u001F':
            case '<':
            case '>':
            case ':':
            case '"':
            case '/':
            case '|':
            case '?':
            case '*':
                builder.Append('_');
                break;
            case '\\':
                builder.Append(containsFolder ? c : '_');
                break;
            default:
                builder.Append(c);
                break;
        }
    }
    string built = builder.ToString();
    if (built == "")
    {
        return "_";
    }
    if (built.EndsWith(" ") || built.EndsWith("."))
    {
        built = built.Substring(0, built.Length - 1) + "_";
    }
    // These are reserved names, in either the folder or file name, but they are fine if following a dot
    // CON, PRN, AUX, NUL, COM0 .. COM9, LPT0 .. LPT9
    builder = new StringBuilder(built.Length + 12);
    index = 0;
    foreach (Match match in Regex.Matches(built, @"(^|\\)\s*(?<bad>CON|PRN|AUX|NUL|COM\d|LPT\d)\s*(\.|\\|$)", RegexOptions.IgnoreCase))
    {
        Group group = match.Groups["bad"];
        if (group.Index > index)
        {
            builder.Append(built.Substring(index, match.Index - index + 1));
        }
        builder.Append(group.Value);
        builder.Append("_");        // putting an underscore after this keyword is enough to make it acceptable
        index = group.Index + group.Length;
    }
    if (index == 0)
    {
        return built;
    }
    if (index < built.Length - 1)
    {
        builder.Append(built.Substring(index));
    }
    return builder.ToString();
}

Antwoord 11

Vanaf 18/04/2017 is er geen simpele zwarte of witte lijst met karakters en bestandsnamen zichtbaar in de antwoorden op dit onderwerp – en er zijn veel reacties.

De beste suggestie die ik kon bedenken was om de gebruikersnaam het bestand te laten noemen zoals hij dat wil. Een foutafhandeling gebruiken wanneer de toepassing het bestand probeert op te slaan, eventuele uitzonderingen opvangen, aannemen dat de bestandsnaam de schuldige is (uiteraard nadat u zeker weet dat het opslagpad ook in orde was), en de gebruiker vragen om een nieuwe bestandsnaam. Voor de beste resultaten plaatst u deze controleprocedure in een lus die doorgaat totdat de gebruiker het goed heeft of opgeeft. Werkte het beste voor mij (tenminste in VBA).


Antwoord 12

Het .NET Framework System.IObiedt de volgende functies voor ongeldige bestandssysteemtekens:

Deze functies moetende juiste resultaten opleveren, afhankelijk van het platform waarop de .NET-runtime wordt uitgevoerd.


Antwoord 13

Ik ging er altijd van uit dat verboden tekens in Windows-bestandsnamen betekenden dat alle exotische tekens ook verboden zouden worden. Vooral het onvermogen om ?,/ en :te gebruiken irriteerde me. Op een dag ontdekte ik dat het vrijwel alleen die chars waren die werden verbannen. Andere Unicode-tekens kunnen worden gebruikt. Dus de Unicode-tekens die het dichtst in de buurt kwamen van de verboden die ik kon vinden, werden geïdentificeerd en MS Word-macro’s werden voor hen gemaakt als Alt+?, Alt+ :enz. Nu vorm ik de bestandsnaam in Word, gebruik de vervangende tekens, en kopieer deze naar de Windows-bestandsnaam. Tot nu toe heb ik geen problemen gehad.

Hier zijn de vervangende tekens (Alt+ de decimale Unicode):

  • ⃰ ⇔ Alt8432
  • ⁄ ⇔ Alt8260
  • ⃥ ⇔ Alt8421
  • ∣ ⇔ Alt8739
  • ⵦ ⇔ Alt11622
  • ⮚ ⇔ Alt11162
  • ‽ ⇔ Alt8253
  • ፡ ⇔ Alt4961
  • ‶ ⇔ Alt8246
  • ″ ⇔ Alt8243

Als test heb ik een bestandsnaam gevormd met al die tekens en Windows accepteerde het.


Antwoord 14

Bij het maken van internetsnelkoppelingen in Windows, om de bestandsnaam te maken, worden illegale tekens overgeslagen, behalve de schuine streep, die wordt omgezet in min.


15

Ik had dezelfde behoefte en was op zoek naar aanbeveling of standaardreferenties en kwam deze thread tegen. Mijn huidige zwarte lijst van tekens die in bestands- en directory-namen moeten worden vermeden, zijn:

$CharactersInvalidForFileName = {
    "pound" -> "#",
    "left angle bracket" -> "<",
    "dollar sign" -> "$",
    "plus sign" -> "+",
    "percent" -> "%",
    "right angle bracket" -> ">",
    "exclamation point" -> "!",
    "backtick" -> "`",
    "ampersand" -> "&",
    "asterisk" -> "*",
    "single quotes" -> "“",
    "pipe" -> "|",
    "left bracket" -> "{",
    "question mark" -> "?",
    "double quotes" -> "”",
    "equal sign" -> "=",
    "right bracket" -> "}",
    "forward slash" -> "/",
    "colon" -> ":",
    "back slash" -> "\\",
    "lank spaces" -> "b",
    "at sign" -> "@"
};

Other episodes