我知道/在Linux中是非法的,以下是Windows中的非法(我认为) *
.
"
/
\
[
]
:
;
|
,
我还想念什么?
但是,我需要一份全面的指南,其中要考虑到双字节字符。链接到外部资源对我来说很好。
我首先需要使用可能包含禁止字符的名称在文件系统上创建目录,因此我计划将这些字符替换为下划线。然后,我需要将此目录及其内容写到一个zip文件中(使用Java),因此有关zip目录名称的任何其他建议将不胜感激。
我知道/在Linux中是非法的,以下是Windows中的非法(我认为) *
.
"
/
\
[
]
:
;
|
,
我还想念什么?
但是,我需要一份全面的指南,其中要考虑到双字节字符。链接到外部资源对我来说很好。
我首先需要使用可能包含禁止字符的名称在文件系统上创建目录,因此我计划将这些字符替换为下划线。然后,我需要将此目录及其内容写到一个zip文件中(使用Java),因此有关zip目录名称的任何其他建议将不胜感激。
Answers:
禁止使用文件名字符的“综合指南”在Windows上不起作用,因为它保留了文件名和字符。是的,*
"
?
禁止像和这样的字符
,但是有无限数量的名称仅由被禁止的有效字符组成。例如,空格和点是有效的文件名字符,但禁止仅由那些字符组成的名称。
Windows不会区分大小写字符,因此,A
如果a
已经存在一个命名的文件夹,则无法创建一个命名的文件夹。更糟的,似乎允许的名称,如PRN
和CON
,以及许多其他名称,是保留的,不允许使用。Windows也有几个长度限制;如果将文件名移动到另一个文件夹,则在一个文件夹中有效的文件名可能变得无效。命名文件和文件夹的规则
在Microsoft文档中。
通常,您不能使用用户生成的文本来创建Windows目录名称。如果你想允许用户他们想要什么名字,你必须创建安全的名字,如A
,AB
,A2
等,存储用户生成的名称和应用程序数据文件的路径等价物,并在你的应用程序中执行路径映射。
如果绝对必须允许用户生成的文件夹名称,则判断它们是否无效的唯一方法是捕获异常并假定名称无效。即使这样也充满了危险,因为拒绝访问,脱机驱动器和驱动器空间不足引发的异常与可以为无效名称引发的异常重叠。您正在打开一罐巨大的伤害。
A.txt
是无效的,因为a.TXT
可能存在。
COPY CON PRN
表示从键盘输入或可能的标准输入中读取,并将其复制到打印机设备。不确定它在现代窗户上是否仍然有效,但是肯定已经存在很长时间了。在过去,您可以使用它来键入文本,并让点矩阵打印机简单地将其输出。
让我们保持简单并首先回答问题。
禁止打印的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)
不可打印字符
如果您的数据来自允许非打印字符的来源,则还有更多要检查的内容。
Linux / Unix:
0 (NULL byte)
视窗:
0-31 (ASCII control characters)
注意:虽然在Linux / Unix文件系统下创建文件名中带有控制字符的文件是合法的,但用户处理此类文件可能是一场噩梦。
保留文件名
保留以下文件名:
视窗:
CON, PRN, AUX, NUL
COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
(既可以单独使用,也可以带有任意文件扩展名LPT1.txt
)。
其他规定
视窗:
文件名不能以空格或点结尾。
在Linux和其他与Unix相关的系统下,文件或目录的名称中不能出现两个字符,它们是NUL '\0'
和slash '/'
。当然,斜杠可以出现在路径名中,分隔目录组件。
谣言1认为Steven Bourne(“ shell”成名)有一个包含254个文件的目录,每个出现在文件名中的单个字母(字符代码)一个,当然/
,'\0'
该名称.
是当前目录)。它用于测试Bourne shell,并经常对诸如备份程序之类的粗心程序造成严重破坏。
其他人已经涵盖了Windows规则。
请注意,MacOS X具有不区分大小写的文件系统。
当史蒂夫·伯恩(Steve Bourne)编写Unix shell(后来称为Bourne shell)时,他创建了一个包含254个文件的目录,每个文件包含一个字符的名称,每个字节值除
'\0'
和斜杠外,两个字符不能在Unix中出现。文件名。他将该目录用于模式匹配和标记化的所有测试方式。(当然,测试目录是由程序创建的。)多年之后,该目录成为文件树遍历程序的祸根。它测试了他们的破坏。
请注意,该目录必须包含.
和..
,因此可以说是253个文件(和2个目录)或255个名称项,而不是254个文件。这不会影响轶事的有效性或它描述的仔细测试。
/
在名称中使用命名。这导致了一些问题,因为它使用该方案创建了一个新目录
PATH
变量中,因为冒号用作分隔符(在Windows上为分号)。因此,此类目录中的程序必须使用指定其所在位置的路径名运行(可以是相对路径,也可以是绝对路径),或者您必须位于该目录中并且在中具有点号(.
即当前目录)PATH
,这被广泛认为是不安全的。
除了创建字符黑名单,您还可以使用白名单。考虑到所有因素,在文件或目录名称上下文中有意义的字符范围非常短,并且除非您有一些非常具体的命名要求,否则如果用户无法使用整个ASCII表,则用户将无法将其保留在应用程序中。
它不能解决目标文件系统中保留名称的问题,但是通过白名单,可以更轻松地减轻源头的风险。
本着这种精神,这是可以认为安全的一系列字符:
以及您希望允许的所有其他安全字符。除此之外,您只需要执行一些有关空格和点的附加规则。通常就足够了:
这已经允许使用非常复杂且荒谬的名称。例如,这些名称可能符合以下规则,并且在Windows / Linux中是有效的文件名:
A...........ext
B -.- .ext
从本质上讲,即使白名单中的字符很少,您仍然应该确定什么才是真正有意义的,并相应地验证/调整名称。在我的一个应用程序中,我使用了与上述相同的规则,但是删除了所有重复的点和空格。
让Windows告诉您答案的简单方法是尝试通过资源管理器重命名文件,然后输入/作为新名称。Windows将弹出一个消息框,告诉您非法字符列表。
A filename cannot contain any of the following characters:
\ / : * ? " < > |
好吧,如果仅出于研究目的,那么最好的选择是查看Filenames上的Wikipedia条目。
如果您想编写一个可移植的函数来验证用户输入并基于此创建文件名,则简短的回答是not。看一下诸如Perl的File :: Spec之类的可移植模块,以瞥见完成这种“简单”任务所需的所有跃点。
对于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
这是基于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();
}
StringBuilder
要用初始容量值进行初始化?2.为什么在长度上加12 filename
?3.是任意选择12个还是在这个数字后面有一些想法?
截至2017年4月18日,此主题的答案中没有简单的黑名单或白名单字符和文件名-并且有很多答复。
我能想到的最好建议是让用户按自己喜欢的方式命名文件。当应用程序尝试保存文件,捕获任何异常,假定文件名被责备时(显然在确保保存路径也确定之后),并使用错误处理程序,并提示用户输入新的文件名。为了获得最佳结果,请将此检查过程放在一个循环中,直到用户正确或放弃为止。最适合我(至少在VBA中)。
虽然唯一非法的Unix字符可能是/
和NULL
,但是应该包括一些有关命令行解释的注意事项。
例如,虽然命名文件1>&2
或2>&1
在Unix上,在命令行上使用时的文件名,例如,这可能被误解。
同样,也可以为文件命名$PATH
,但是当尝试从命令行访问文件时,shell将转换$PATH
为其变量值。
$'myvalueis'
,例如:$ echo 'hi' > $'2>&1'
,cat 2\>\&1
“喜”
与界定困难,什么是合法的,而不是被已经不客气和白名单被提出。但是Windows 支持8位以上的字符。维基百科指出,(例如)
修饰符字母结肠 [(见下面7.)被]有时在Windows文件名使用,因为它是相同的在结肠的Segoe UI字体用于文件名。不允许使用[继承的ASCII]冒号。
因此,我想提出一种使用Unicode字符替代“非法”字符的更为自由的方法。我在可比较的用例中发现了结果,可读性更高。例如看这个块。另外,您甚至可以从中还原原始内容。下表提供了可能的选择和研究:
U+002A * ASTERISK
),您可以使用许多之一上市,例如U+2217 ∗ (ASTERISK OPERATOR)
或Full Width Asterisk U+FF0A *
⋅ U+22C5 dot operator
“ U+201C english leftdoublequotemark
(替代方法请参见此处)/ SOLIDUS U+002F
),您可以使用∕ DIVISION SLASH U+2215
(其他此处)\ U+005C Reverse solidus
),您可以使用⧵ U+29F5 Reverse solidus operator
(更多)U+005B Left square bracket
)和](U+005D Right square bracket
),可以使用例如U+FF3B[ FULLWIDTH LEFT SQUARE BRACKET
与U+FF3D ]FULLWIDTH RIGHT SQUARE BRACKET
(从这里,更多的可能性在这里)U+2236 ∶ RATIO (for mathematical usage)
或U+A789 ꞉ MODIFIER LETTER COLON
,(请参阅冒号(字母),有时在Windows文件名中使用,因为它与用于文件名的Segoe UI字体中的冒号相同。不允许冒号本身)(请参见此处))U+037E ; GREEK QUESTION MARK
(请参见此处)U+0964 । DEVANAGARI DANDA
,U+2223 ∣ DIVIDES
或U+01C0 ǀ LATIN LETTER DENTAL CLICK
(维基百科)。还有盒子的绘图字符包含各种其他选项。, U+002C COMMA
)‚ U+201A SINGLE LOW-9 QUOTATION MARK
(请参阅此处)U+003F ? QUESTION MARK
),这些人是很好的候选人:U+FF1F ? FULLWIDTH QUESTION MARK
或U+FE56 ﹖ SMALL QUESTION MARK
(从(他在re的基础上,在Dingbats Block的另外两个人中,搜索“问题”))在Windows中创建Internet快捷方式时,要创建文件名,它会跳过非法字符,但正斜杠除外,正斜杠会转换为负号。
在Unix Shell中,几乎所有的字符都可以用单引号引起来'
。除了单引号本身,您不能表达控制字符,因为\
它没有被扩展。可以从带引号的字符串中访问单引号本身,因为您可以将字符串与单引号和双引号连接起来,例如'I'"'"'m'
可以用来访问名为"I'm"
(这里也可以使用双引号)。
因此,应避免使用所有控制字符,因为它们很难在shell中输入。其余的部分仍然很有趣,特别是以破折号开头的文件,因为大多数命令将这些选项作为选项读取,除非您--
之前有两个破折号,或者./
用来指定它们,这也隐藏了开始-
。
如果您想变得很好,请不要将shell和典型命令使用的任何字符用作语法元素,有时取决于位置,因此例如,您仍然可以使用-
,但不能用作第一个字符;与相同.
,您只能将其用作第一个字符(“隐藏文件”)。刻薄地说,您的文件名是VT100转义序列;-),因此ls使输出乱码。
我有同样的需求,正在寻找推荐或标准参考,并遇到了这个问题。我当前应在文件和目录名称中避免使用的字符黑名单为:
$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" -> "@"
};
@
列表中的内容发表评论吗?
b
?大声笑,我想那是b的lank spaces
……还剩下一些……我重命名了图片,(),-.;[]^_~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ.jpg
但由于它看上去很生气而不得不将其改回……
echo abc > "ab.;,=[1]"