我知道在Linux中“/”是非法的,而在Windows中,"*" "\" "<" ">" ":" "|" "?" 是非法的。
还有其他什么我需要注意的吗?我需要一份全面的指南,也要考虑双字节字符。
被禁止的可打印ASCII字符包括:
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)
不可打印字符
如果你的数据来自允许使用不可打印字符的数据源,则需要进行更多的检查。
Linux/Unix:
0 (NULL byte)
Windows:
0-31 (ASCII control characters)
注意:虽然在Linux/Unix文件系统下创建包含控制字符的文件名是合法的,但对于用户来说,处理这些文件可能会成为噩梦。
保留文件名
以下文件名是保留的:
Windows:
CON, PRN, AUX, NUL
COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
(无论是单独使用还是带有任意文件扩展名,例如LPT1.txt
)。
其他规则
Windows:
文件名不能以空格或点结束。
macOS:
您没有要求,但以防万一:冒号:
和正斜杠/
根据上下文不允许使用(例如Finder支持斜杠,终端支持冒号)。 (更多详情)
*?<>"
这些字符被保留为“通配符字符”(wildcard characters),这是由于特殊的设计决策,要求文件系统在实现NtQueryDirectoryFile
系统调用时,在其低层级上过滤目录列表。在POSIX系统中,这是在应用程序级别上实现的。 - Eryk Sunlpt1
和lpt1.txt
。 然后尝试在Windows资源管理器中删除它们:您无法删除。或者在cmd.exe
中:也无法删除。但是Cygwin可以删除。这似乎是一个被人工维护的20世纪80年代限制。 - Lutz Prechelt*
、"
、?
等字符是被禁止的,但只由有效字符组成的名称却有无限个被禁止。例如,空格和点是有效的文件名字符,但是只由这些字符组成的名称是被禁止的。a
的文件夹,您就无法创建名为A
的文件夹。更糟糕的是,看似允许的名称如PRN
和CON
以及许多其他名称都是保留的并且不允许使用。Windows还有几个长度限制;在一个文件夹中有效的文件名,如果移到另一个文件夹中可能会变得无效。命名文件和文件夹的规则在Microsoft文档中。A
、AB
、A2
等安全名称,将用户生成的名称及其路径等效存储在应用程序数据文件中,并在应用程序中执行路径映射。A.txt
这样的文件名是“无效的”,因为可能存在 a.TXT
。 - BorodinCOPY CON PRN
的意思是从键盘输入(或者可能是标准输入)读取内容,并将其复制到打印机设备上。不确定在现代的Windows系统中是否仍然有效,但长期以来肯定可以使用。在早期,你可以使用它来输入文本并使点阵式打印机简单地输出它。 - AntonPiatek在Linux和其他Unix相关系统中,文件或目录名称中传统上只有两个字符是不允许出现的,它们分别是NUL '\0'
和斜杠'/'
。当然,斜杠可以出现在路径名中,用于分隔目录组件。
传闻1称,史蒂文·伯恩(“shell”的创始人)曾经拥有一个包含254个文件的目录,每个文件名都包含可以出现在文件名中的每个字母(字符代码),但不包括/
、'\0'
;而名称.
代表当前目录。这个目录被用来测试Bourne shell,并经常对备份程序等不谨慎的程序造成破坏。
其他 人员已经介绍了Windows文件名的规则,并提供了有关该主题的Microsoft和Wikipedia链接。
请注意,MacOS X 具有不区分大小写的文件系统。当前版本似乎允许在文件名中使用冒号 “:”,但历史上并非总是这样。$ echo a:b > a:b
$ ls -l a:b
-rw-r--r-- 1 jonathanleffler staff 4 Nov 12 07:38 a:b
$
然而,至少在macOS Big Sur 11.7中,文件系统不允许使用无效的UTF-8字符串作为文件名。这意味着文件名不能由UTF-8中始终无效的字节(0xC0、0xC1、0xF5-0xFF)组成,并且您不能将连续字节0x80..0xBF作为文件名中唯一的字节。错误代码为92,非法字节序列。
POSIX定义了一个可移植文件名字符集,包括:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 . _ -
如果坚持使用仅由这些字符组成的名称,就可以避免大多数问题,尽管Windows仍会添加一些复杂性。
当Steve Bourne编写他的Unix shell(后来被称为Bourne shell)时,他创建了一个包含254个文件的目录,每个文件名只有一个字符,分别代表除了
'\0'
和斜杠之外的每个字节值。他使用该目录进行各种模式匹配和标记化测试。(当然,测试目录是由程序创建的。)多年以后,那个目录成为了遍历文件树程序的噩梦;它将它们测试到了崩溃。
请注意,该目录必须包含条目 .
和 ..
,因此它可能是253个文件(和2个目录),或255个名称条目,而不是254个文件。这并不影响这个轶事的有效性,也不影响它所描述的仔细测试。
TPOP先前在http://plan9.bell-labs.com/cm/cs/tpop和http://cm.bell-labs.com/cm/cs/tpop,但两者现在(2021-11-12)均无法使用。 此外,请参考维基百科关于TPOP的内容。
不必创建一个字符黑名单,可以使用白名单。总体来说,在文件或目录名称上下文中具有意义的字符范围相当短,除非您有一些非常特定的命名要求,否则如果用户不能使用整个 ASCII 表,他们不会反感您的应用程序。
这并不能解决目标文件系统中保留名称的问题,但是通过白名单可以更容易地在源头上减轻风险。
基于此,以下是可以考虑为安全的字符范围:
以及您希望允许的任何其他安全字符。除此之外,您只需强制执行一些关于空格和点的附加规则。这通常足够了:
这已经允许相当复杂和荒谬的名称。例如,使用这些规则,以下名称将在 Windows/Linux 中成为有效文件名:
A...........ext
B -.- .ext
实际上,即使只有如此少量的白名单字符,您仍然应该决定什么实际上是有意义的,并相应地验证/调整名称。在我的一个应用程序中,我使用了与上述相同的规则,但剥离了任何重复的点和空格。
\
。Windows将弹出一个消息框告诉您非法字符的列表:如果仅出于研究目的,那么您最好查看文件名的保留字符和词语的维基百科条目。
如果您想编写一个可移植的函数来验证用户输入并基于此创建文件名,简短的答案是不要这样做。查看类似Perl的File::Spec这样的可移植模块可以了解完成这样一个“简单”任务所需的所有步骤。
对于定义“什么是合法和非法”的困难已经得到解决,并且已经提出了白名单建议。但不仅仅是Windows,许多类Unix操作系统也支持Unicode等多于8位的字符。在这里,你还可以谈论诸如UTF-8的编码。你可以考虑Jonathan Leffler的评论,他提供了关于现代Linux和描述MacOS细节的信息。维基百科指出,(例如)
修改字母冒号(见下文第7点)有时会在Windows文件名中使用,因为它与用于文件名的Segoe UI字体中的冒号完全相同。而继承自ASCII的冒号本身是不允许的。角色名称 | 原始代码 | 原始字符 | 全角代码 | 全角字符 | 小写形式变体 | 小写形式变体代码 |
---|---|---|---|---|---|---|
1. 星号 | U+2A | * |
U+FF0A | * |
﹡ |
U+FE61 |
2. 句号 | U+2E | . |
U+FF0E | . |
﹒ |
U+FE52 |
3. 引号 | U+22 | " |
U+FF02 | " |
无 | |
4. 反斜杠 | U+5C | \ |
U+FF3C | \ |
﹨ |
U+FE68 |
5. 斜杠 | U+2F | / |
U+FF0F | / |
无 | |
6.1. 左方括号 | U+5B | [ |
U+FF3B | [ |
﹝ (仅乌龟) |
U+FE5D |
6.2. 右方括号 | U+5D | ] |
U+FF3D | ] |
﹞ (仅乌龟) |
U+FE5E |
7. 冒号 | U+3A | : |
U+FF3A | : |
﹕ |
U+FE55 |
8. 分号 | U+3B | ; |
U+FF1B | ; |
﹔ |
U+FE54 |
9. 竖线 | U+7C | | |
U+FF5C | | |
无 | |
10. 逗号 | U+2C | , |
U+FF0C | , |
﹐ |
U+FE50 |
11. 问号 | U+3F | ? |
U+FF1F | ? |
﹖ |
U+FE56 |
12.1. 大于号 | U+3E | > |
U+FF1E | > |
﹥ |
U+FE65 |
12.2. 小于号 | U+3C | < |
U+FF1C | < |
﹤ |
U+FE64 |
13. 抑扬符号 | U+5E | ^ |
U+FF3E | ^ |
无 |
0x
)来将数字表示反向转换为Unicode字符(请记得将下面的代码点基数设置为十进制或十六进制):?*:altpipe::{U+2D4F}
,以输入字符串altpipe
时自动替换为字符ⵏ
- 这是我输入这些特殊字符的方法,如果有共同兴趣,我可以分享我的Autohotkey脚本你对更宽的字符不满意吗?有很多替代方案。请注意:十六进制数表示对大小写不敏感,前导零可以随意添加或省略,所以例如U+002A
和u+2a
是等效的。如果有的话,我会尽量指出更多信息或替代方案-请随时向我展示更多或更好的选择。
不要使用*(U+2A * ASTERISK
),你可以使用列出的众多选项之一,例如U+2217 ∗(ASTERISK OPERATOR)
或全角星号U+FF0A *
。符号的组合变音符号中的u+20f0 ⃰ combining asterisk above
也是一个有效的选择。关于组合字符的更多信息,请参阅第4点。
不要使用.(U+2E . full stop
),你可以选择这些选项之一,例如⋅ U+22C5 dot operator
。
不要使用"(U+22 " quotation mark
),你可以使用“ U+201C english leftdoublequotemark
,更多的替代方案请参见这里。我还包括了Wally Brockway的回答中的一些建议,例如u+2036 ‶ reversed double prime
和u+2033 ″ double prime
- 从现在开始,我将用¹⁴来表示该来源的想法。
不要使用/(U+2F / SOLIDUS
),你可以使用∕ DIVISION SLASH U+2215
(其他选项在这里)或u+2044 ⁄ fraction slash
¹⁴。你还可以尝试使用̸ U+0338 COMBINING LONG SOLIDUS OVERLAY
或̷ COMBINING SHORT SOLIDUS OVERLAY U+0337
,但要注意一些字符的间距,包括combining
或overlay
字符。它们本身没有宽度,可能会产生像这样的结果 --> ̸th̷is,即̸_th̷_is
(为了说明,在这6个字符中添加了下划线)。添加空格后,你会得到 --> ̸ th ̷ is,即̸ _th ̷ _is
(加了两个空格,总共8个字符)。第二个(COMBINING SHORT SOLIDUS OVERLAY
)在stackoverflow字体中看起来很糟糕。
不要使用\
(U+5C Reverse solidus
),你可以使用⧵ U+29F5 Reverse solidus operator
(更多选项)或u+20E5 ⃥ combining reverse solidus overlay
¹⁴。
要替换[(U+5B [ Left square bracket
)和](U+005D ] Right square bracket
),你可以使用例如U+FF3B[ FULLWIDTH LEFT SQUARE BRACKET
和U+FF3D ]FULLWIDTH RIGHT SQUARE BRACKET
(来自这里,更多选择在这里)。
不要使用:(u+3a : colon
),你可以使用U+2236 ∶ RATIO(用于数学用途)
或U+A789 ꞉ MODIFIER LETTER COLON
(参见冒号(字母),有时在Windows文件名中使用,因为它与用于文件名的Segoe UI字体中的冒号相同。冒号本身是不允许的...更多的替代方案请参见这里)。另一个选择是u+1361 ፡ ethiopic wordspace
¹⁴。
不要使用;(u+3b ; semicolon
),你可以使用U+037E ; GREEK QUESTION MARK
(参见这里)。
对于|(u+7c | vertical line
),有一些很好的替代品,例如:U+2223 ∣ DIVIDES
,U+0964 । DEVANAGARI DANDA
,U+01C0 ǀ LATIN LETTER DENTAL CLICK
(最后两个来自维基百科),或者U+2D4F ⵏ Tifinagh Letter Yan
。方框绘图字符中还包含其他各种选项。
不要使用,(, U+002C COMMA
),你可以使用例如‚ U+201A SINGLE LOW-9 QUOTATION MARK
(参见这里)。
对于?(U+003F ? QUESTION MARK
),这些是很好的候选项:U+FF1F ? FULLWIDTH QUESTION MARK
或U+FE56 ﹖ SMALL QUESTION MARK
(来自这里和这里)。Dingbats Block中还有两个(搜索“question”),以及u+203d ‽ interrobang
¹⁴。
虽然我的机器似乎可以接受它而不变,但为了完整起见,我还是想包括>
(u+3e greater-than sign
)和<
(u+3c less-than sign
)。这里最好的替代品可能也来自引用块,例如u+203a › single right-pointing angle quotation mark
和u+2039 ‹ single left-pointing angle quotation mark
。tifinagh块只包含ⵦ(u+2D66)
¹⁴来替换<
。最后一个提法是⋖ less-than with dot u+22D6
和⋗ greater-than with dot u+22D7
。
对于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
寻找正则表达式的人:
const BLACKLIST = /[<>:"\/\\|?*]/g;
echo abc > "ab.;,=[1]"
。 - dolmen