Windows和Linux目录名称中禁止使用什么字符?


355

我知道/在Linux中是非法的,以下是Windows中的非法(我认为) * . " / \ [ ] : ; | ,

我还想念什么?

但是,我需要一份全面的指南,其中要考虑到双字节字符。链接到外部资源对我来说很好。

我首先需要使用可能包含禁止字符的名称在文件系统上创建目录,因此我计划将这些字符替换为下划线。然后,我需要将此目录及其内容写到一个zip文件中(使用Java),因此有关zip目录名称的任何其他建议将不胜感激。


13
您提到的某些字符实际上在Windows上是允许的。检查此内容:echo abc > "ab.;,=[1]"
dolmen

3
同样不要忘记<和>在Windows上是非法的。
AnotherParker

4
/在Linux中不是非法的。你只需要在打字的时候可以用\逃吧。
戴维·毕晓普

5
@ DavidC.Bishop:这篇SO文章断言Linux内核将阻止您使用包含斜杠的文件名。你有能力使它起作用吗?
索伦·比约恩斯塔德

14
“ /在Linux中不是非法的。您只需在输入时使用\对其进行转义” –这句话是完全错误的。文件名组件不能包含/,并且转义它无效。
吉姆·巴尔特

Answers:


215

禁止使用文件名字符的“综合指南”在Windows上不起作用,因为它保留了文件名和字符。是的,* " ?禁止像和这样的字符 ,但是有无限数量的名称仅由被禁止的有效字符组成。例如,空格和点是有效的文件名字符,但禁止仅由那些字符组成的名称。

Windows不会区分大小写字符,因此,A如果a已经存在一个命名的文件夹,则无法创建一个命名的文件夹。更糟的,似乎允许的名称,如PRNCON,以及许多其他名称,是保留的,不允许使用。Windows也有几个长度限制;如果将文件名移动到另一个文件夹,则在一个文件夹中有效的文件名可能变得无效。命名文件和文件夹的规则 在Microsoft文档中。

通常,您不能使用用户生成的文本来创建Windows目录名称。如果你想允许用户他们想要什么名字,你必须创建安全的名字,如AABA2等,存储用户生成的名称和应用程序数据文件的路径等价物,并在你的应用程序中执行路径映射。

如果绝对必须允许用户生成的文件夹名称,则判断它们是否无效的唯一方法是捕获异常并假定名称无效。即使这样也充满了危险,因为拒绝访问,脱机驱动器和驱动器空间不足引发的异常与可以为无效名称引发的异常重叠。您正在打开一罐巨大的伤害。


11
MSDN链接中的关键词是“和目标文件系统不允许的其他任何字符”。Windows上可能有不同的文件系统。有些可能允许Unicode,有些则不允许。通常,验证名称的唯一安全方法是在目标设备上尝试该名称。
阿德里安·麦卡锡

72
有一些准则,并且“有无限数量的名称仅由被禁止的有效字符组成”不是建设性的。同样的“Windows不大写之间区分小写字符”是一个愚蠢的例外-在OP是询问语法而不是语义,并没有正义感的人会说,像一个文件名A.txt无效的,因为a.TXT可能存在。
Borodin

9
COPY CON PRN表示从键盘输入或可能的标准输入中读取,并将其复制到打印机设备。不确定它在现代窗户上是否仍然有效,但是肯定已经存在很长时间了。在过去,您可以使用它来键入文本,并让点矩阵打印机简单地将其输出。
AntonPiatek '16

6
“不是建设性的”-相反,这是事实。没有什么建设性的是鲍罗丁的好战。
Jim Balter

3
“通常,您不能使用用户生成的文本来创建Windows目录名称。” <-如果要执行此操作,您可以只拥有一个角色白名单,并且如果您可以忽略已经存在的问题,它将在很大程度上起作用。
Casey

531

让我们保持简单并首先回答问题。

  1. 禁止打印的ASCII字符是:

    • Linux / Unix:

      / (forward slash)
      
    • 视窗:

      < (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. 不可打印字符

    如果您的数据来自允许非打印字符的来源,则还有更多要检查的内容。

    • Linux / Unix:

      0 (NULL byte)
      
    • 视窗:

      0-31 (ASCII control characters)
      

    注意:虽然在Linux / Unix文件系统下创建文件名中带有控制字符的文件是合法的,但用户处理此类文件可能是一场噩梦

  3. 保留文件名

    保留以下文件名:

    • 视窗:

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

      (既可以单独使用,也可以带有任意文件扩展名LPT1.txt)。

  4. 其他规定

    • 视窗:

      文件名不能以空格或点结尾。


5
大多数Windows文件系统不限于8位字符。Windows上还有许多其他8位字符(NUL,控制字符)被禁止。即使考虑到这些问题,提问者也无法按照他的要求“在文件系统上创建目录”,因为有无数个无效的目录名称由非禁止字符组成。
高高拱门

38
其他人已经说过了,这不是建设性的。当我来到这里寻找答案时,我希望我不得不在其他地方收集该列表:在尝试使用有效的文件名尝试从用户输入中过滤掉哪些字符。字符是否一起变为无效的问题,也可能需要详细说明。
Christopher Oezbek,2015年

5
在Linux上也禁止使用NULL字符。
丹·琼斯

3
Linux上不禁止使用换行符。我认为它们应该是……但是,如果NUL在Linux上被禁止,那么在Windows上被禁止,则可以达到相同的目的。
阿尔卡罗

11
@Soaku:当然不是,因为世界并不是围绕微软发展的。当只有两个绝对禁止的字符时,为什么要添加不必要的限制?
firegurafiku

67

在Linux和其他与Unix相关的系统下,文件或目录的名称中不能出现两个字符,它们是NUL '\0'和slash '/'。当然,斜杠可以出现在路径名中,分隔目录组件。

谣言1认为Steven Bourne(“ shell”成名)有一个包含254个文件的目录,每个出现在文件名中的单个字母(字符代码)一个,当然/'\0'该名称.是当前目录)。它用于测试Bourne shell,并经常对诸如备份程序之类的粗心程序造成严重破坏。

其他人已经涵盖了Windows规则。

请注意,MacOS X具有不区分大小写的文件系统。


1《编程实践》中的 Kernighan&Pike在第6章,测试,第6.5节“压力测试”中说了很多:

当史蒂夫·伯恩(Steve Bourne)编写Unix shell(后来称为Bourne shell)时,他创建了一个包含254个文件的目录,每个文件包含一个字符的名称,每个字节值除'\0'和斜杠外,两个字符不能在Unix中出现。文件名。他将该目录用于模式匹配和标记化的所有测试方式。(当然,测试目录是由程序创建的。)多年之后,该目录成为文件树遍历程序的祸根。它测试了他们的破坏。

请注意,该目录必须包含...,因此可以说是253个文件(和2个目录)或255个名称项,而不是254个文件。这不会影响轶事的有效性或它描述的仔细测试。


1
254个文件?utf8呢?
j_kubik 2012年

20
254个文件均为单字符文件名,文件名中允许的每个字符一个。当史蒂夫·伯恩(Steve Bourne)编写伯恩(Bourne)外壳时,UTF-8甚至还没有闪闪发光。UTF-8施加有关字节有效序列的规则(并且完全不允许字节0xC0、0xC1、0xF5-0xFF)。否则,它并没有太大区别-在我正在讨论的细节级别上。
乔纳森·勒夫勒

1
MacOS HFS +文件系统的磁盘目录分隔符实际上是':'而不是'/'。当您使用* nix API时,操作系统通常(可能总是)执行正确的操作。但是,如果您要迁移到OSX世界(例如使用applescript),请不要期望这种情况会可靠地发生。看起来Cocoa API可能也使用/并隐藏了:,但是我敢肯定旧的Carbon API不会。
Dan Pritts 2013年

@DanPritts我在Xcode的首选项中创建了一个自定义字体/配色方案,并/在名称中使用命名。这导致了一些问题,因为它使用该方案创建了一个新目录
Andreas

请注意,如果目录名称中带有冒号,则不能将目录添加到Unix PATH变量中,因为冒号用作分隔符(在Windows上为分号)。因此,此类目录中的程序必须使用指定其所在位置的路径名运行(可以是相对路径,也可以是绝对路径),或者您必须位于该目录中并且在中具有点号(.即当前目录)PATH,这被广泛认为是不安全的。
乔纳森·莱夫勒

36

除了创建字符黑名单,您还可以使用白名单。考虑到所有因素,在文件或目录名称上下文中有意义的字符范围非常短,并且除非您有一些非常具体的命名要求,否则如果用户无法使用整个ASCII表,则用户将无法将其保留在应用程序中。

它不能解决目标文件系统中保留名称的问题,但是通过白名单,可以更轻松地减轻源头的风险。

本着这种精神,这是可以认为安全的一系列字符:

  • 字母(az AZ)-如果需要,也可以使用Unicode字符
  • 数字(0-9)
  • 下划线(_)
  • 连字号(-)
  • 空间
  • 点(。)

以及您希望允许的所有其他安全字符。除此之外,您只需要执行一些有关空格和点的附加规则。通常就足够了:

  • 名称必须包含至少一个字母或数字(以避免仅点/空格)
  • 名称必须以字母或数字开头(以避免前导点/空格)
  • 名称不能以点或空格结尾(如资源管理器所做的那样,请简单地修剪点或空格)

这已经允许使用非常复杂且荒谬的名称。例如,这些名称可能符合以下规则,并且在Windows / Linux中是有效的文件名:

  • A...........ext
  • B -.- .ext

从本质上讲,即使白名单中的字符很少,您仍然应该确定什么才是真正有意义的,并相应地验证/调整名称。在我的一个应用程序中,我使用了与上述相同的规则,但是删除了所有重复的点和空格。


15
那我的非英语用户又会怎么办呢?
pkh

2
@pkh:正如我在帖子中提到的那样,您将在白名单中包含所有需要的unicode字符。通常可以很容易地指定字符范围,尤其是在使用正则表达式的情况下。
AeonOfTime

2
我们使用白名单方法,但是请不要忘记在Windows上必须管理保留的,大小写无关的字符串,例如设备名称(prn,lpt1,con)和。和..
tahoar,2016年

2
您已经错过了Windows限制:不得以点或空格结尾。
马丁·邦纳

1
“考虑到所有因素,在文件或目录名称上下文中有意义的字符范围非常短。” 也许对于某些用例。我正在一个项目中,该项目现在涉及20种语言的媒体文件,文件名需要反映媒体项目的标题,因为最终用户将以这种方式找到内容。许多名称使用标点符号。对文件名字符的任何限制都会带来代价,因此在这种情况下,我们必须最小化限制。在这种用例中,文件名中没有意义的字符范围比那些没有意义的字符范围更短,更简单。
LarsH

29

让Windows告诉您答案的简单方法是尝试通过资源管理器重命名文件,然后输入/作为新名称。Windows将弹出一个消息框,告诉您非法字符列表。

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

https://support.microsoft.com/zh-CN/kb/177506


28

好吧,如果仅出于研究目的,那么最好的选择是查看Filenames上的Wikipedia条目

如果您想编写一个可移植的函数来验证用户输入并基于此创建文件名,则简短的回答是not。看一下诸如Perl的File :: Spec之类的可移植模块,以瞥见完成这种“简单”任务所需的所有跃点。


5

对于Windows,您可以使用PowerShell进行检查

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

要显示UTF-8代码,您可以转换

$enc = [system.Text.Encoding]::UTF8
$PathInvalidChars | foreach { $enc.GetBytes($_) }

$FileNameInvalidChars = [System.IO.Path]::GetInvalidFileNameChars() #41 chars

$FileOnlyInvalidChars = @(':', '*', '?', '\', '/') #5 chars - as a difference

对于那些不讲PowershelI的人,$ FileNameInvalidChars是0x00到0x1F,并且:“ <> | *?\ /
Robin Davies

4

在Windows 10(2019)中,尝试输入以下字符时会出现错误:

文件名不能包含以下任何字符:

\ / : * ? " < > |


3

这是基于Christopher Oezbek的答案的 Windows的ac#实现

containsFolder布尔值使它变得更加复杂,但希望可以涵盖所有内容

/// <summary>
/// This will replace invalid chars with underscores, there are also some reserved words that it adds underscore to
/// </summary>
/// <remarks>
/// /programming/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();
}

我有三个问题:1.为什么StringBuilder要用初始容量值进行初始化?2.为什么在长度上加12 filename?3.是任意选择12个还是在这个数字后面有一些想法?
iiminov

2

截至2017年4月18日,此主题的答案中没有简单的黑名单或白名单字符和文件名-并且有很多答复。

我能想到的最好建议是让用户按自己喜欢的方式命名文件。当应用程序尝试保存文件,捕获任何异常,假定文件名被责备时(显然在确保保存路径也确定之后),并使用错误处理程序,并提示用户输入新的文件名。为了获得最佳结果,请将此检查过程放在一个循环中,直到用户正确或放弃为止。最适合我(至少在VBA中)。


1
从技术角度来看,您的答案@FCastro是正确的。但是,从UX的角度来看,这是一场噩梦-用户不得不一次又一次地玩“输入一些内容,我会告诉你是否成功”游戏。我宁愿看到一条消息(警告样式),告诉用户他们输入了非法字符,稍后将其转换。
迈克(Mike)

克里斯托弗·奥兹别克(Christopher Oezbek)在2015
吉姆

1

虽然唯一非法的Unix字符可能是/NULL,但是应该包括一些有关命令行解释的注意事项。

例如,虽然命名文件1>&22>&1在Unix上,在命令行上使用时的文件名,例如,这可能被误解。

同样,也可以为文件命名$PATH,但是当尝试从命令行访问文件时,shell将转换$PATH为其变量值。


在BASH文字,最好的办法我发现不使用插值进行申报文本$'myvalueis',例如:$ echo 'hi' > $'2>&1'cat 2\>\&1“喜”
ThorSummoner

1

与界定困难,什么是合法的,而不是已经不客气和白名单被提出。但是Windows 支持8位以上的字符。维基百科指出,(例如)

修饰符字母结肠 [(见下面7.)被]有时在Windows文件名使用,因为它是相同的在结肠的Segoe UI字体用于文件名。不允许使用[继承的ASCII]冒号。

因此,我想提出一种使用Unicode字符替代“非法”字符的更为自由的方法。我在可比较的用例中发现了结果,可读性更高。例如看这个块。另外,您甚至可以从中还原原始内容。下表提供了可能的选择和研究:

  1. 相反的*U+002A * ASTERISK),您可以使用许多之一上市,例如U+2217 ∗ (ASTERISK OPERATOR)Full Width Asterisk U+FF0A *
  2. 相反的.,你可以使用的一个,这些,例如⋅ U+22C5 dot operator
  3. 除了",您可以使用“ U+201C english leftdoublequotemark(替代方法请参见此处
  4. 除了// SOLIDUS U+002F),您可以使用∕ DIVISION SLASH U+2215(其他此处
  5. 除了\\ U+005C Reverse solidus),您可以使用⧵ U+29F5 Reverse solidus operator更多
  6. 相反的[U+005B Left square bracket)和]U+005D Right square bracket),可以使用例如U+FF3B[ FULLWIDTH LEFT SQUARE BRACKETU+FF3D ]FULLWIDTH RIGHT SQUARE BRACKET(从这里,更多的可能性在这里
  7. 代替:,您可以使用U+2236 ∶ RATIO (for mathematical usage)U+A789 ꞉ MODIFIER LETTER COLON,(请参阅冒号(字母),有时在Windows文件名中使用,因为它与用于文件名的Segoe UI字体中的冒号相同。不允许冒号本身)(请参见此处)
  8. 除了;,您可以使用U+037E ; GREEK QUESTION MARK(请参见此处
  9. 对于|,有一些很好的替代品,如:U+0964 । DEVANAGARI DANDAU+2223 ∣ DIVIDESU+01C0 ǀ LATIN LETTER DENTAL CLICK维基百科)。还有盒子的绘图字符包含各种其他选项。
  10. 您可以使用(例如)代替,, U+002C COMMA‚ U+201A SINGLE LOW-9 QUOTATION MARK(请参阅此处
  11. 对于?U+003F ? QUESTION MARK),这些人是很好的候选人:U+FF1F ? FULLWIDTH QUESTION MARKU+FE56 ﹖ SMALL QUESTION MARK(从(他在re的基础上,在Dingbats Block的另外两个人中,搜索“问题”))

0

在Windows中创建Internet快捷方式时,要创建文件名,它会跳过非法字符,但正斜杠除外,正斜杠会转换为负号。


3
“没有答案。。。拒绝-主持人检查了您的举报,但没有证据支持。” 你在开玩笑吧。请更好的主持人。
吉姆·巴尔特

-1

在Unix Shell中,几乎所有的字符都可以用单引号引起来'。除了单引号本身,您不能表达控制字符,因为\它没有被扩展。可以从带引号的字符串中访问单引号本身,因为您可以将字符串与单引号和双引号连接起来,例如'I'"'"'m'可以用来访问名为"I'm"(这里也可以使用双引号)。

因此,应避免使用所有控制字符,因为它们很难在shell中输入。其余的部分仍然很有趣,特别是以破折号开头的文件,因为大多数命令将这些选项作为选项读取,除非您--之前有两个破折号,或者./用来指定它们,这也隐藏了开始-

如果您想变得很好,请不要将shell和典型命令使用的任何字符用作语法元素,有时取决于位置,因此例如,您仍然可以使用-,但不能用作第一个字符;与相同.,您只能将其用作第一个字符(“隐藏文件”)。刻薄地说,您的文件名是VT100转义序列;-),因此ls使输出乱码。


问题不在于壳。
Jim Balter

-8

我有同样的需求,正在寻找推荐或标准参考,并遇到了这个问题。我当前应在文件和目录名称中避免使用的字符黑名单为:

$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" -> "@"
};

4
您介意对@列表中的内容发表评论吗?
PypeBros

8
问题是哪些字符是非法的。您列表中的大多数字符都是合法的。
Nigel Alderton'1

6
这封信b?大声笑,我想那是b的lank spaces……还剩下一些……我重命名了图片,(),-.;[]^_~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ.jpg但由于它看上去很生气而不得不将其改回……
ashleedawg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.