当前位置:  开发笔记 > 编程语言 > 正文

如何从任意字符串生成有效的Windows文件名?

如何解决《如何从任意字符串生成有效的Windows文件名?》经验,为你挑选了8个好方法。

我有一个像"Foo:Bar"这样的字符串我想用作文件名,但在Windows上,文件名中不允许使用":"字符.

有没有一种方法可以将"Foo:Bar"变成像"Foo-Bar"这样的东西?



1> Diego Jancic..:

尝试这样的事情:

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}

编辑:

由于GetInvalidFileNameChars()将返回10或15个字符,最好使用StringBuilder而不是简单的字符串; 原始版本将花费更长时间并消耗更多内存.


在字符串中有2个以上不同的无效字符的概率非常小,以至于关心string.Replace()的性能是没有意义的.
InvalidFileNameChars = new char [] {'"','<','>','|','\ 0','\ x0001','\ x0002','\ x0003','\ x0004','\ x0005','\ x0006','\ a','\ b','\ t','\n','\ v','\ f','\ r','\ x000e','\ x000f','\ x0010','\ x0011','\ x0012','\ x0013','\ x0014','\ x0015','\ x0016','\ x0017','\ x0018','\ x0019','\ x001a','\ x001b','\ x001c','\ x001d','\ x001e','\ x001f',':','*','?','\\', '/'};

2> Phil Price..:
fileName = fileName.Replace(":", "-") 

但是":"并不是Windows的唯一非法字符.你还必须处理:

/, \, :, *, ?, ", <, > and |

这些包含在System.IO.Path.GetInvalidFileNameChars();

另外(在Windows上),"." 不能是文件名中唯一的字符(".","..","..."等都无效).使用"."命名文件时要小心,例如:

echo "test" > .test.

将生成一个名为".test"的文件

最后,如果你真的想要正确地做事,你需要注意一些特殊的文件名.在Windows上,您无法创建名为的文件:

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.


此外,对于它的价值,你不能创建一个以这些保留名称之一开头的文件名,后跟一个小数.即con.air.avi
我从来不知道保留的名字.虽然有道理

3> Joseph Gabri..:

这不是更有效,但它更有趣:)

    var fileName = "foo:bar";
    var invalidChars = System.IO.Path.GetInvalidFileNameChars();
    var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray());



4> Qwertie..:

如果有人想要基于的优化版本StringBuilder,请使用此功能.包括rkagerer的诀窍作为选项.

static char[] _invalids;

/// Replaces characters in text that are not allowed in 
/// file names with the specified replacement character.
/// Text to make into a valid filename. The same string is returned if it is valid already.
/// Replacement character, or null to simply remove bad characters.
/// Whether to replace quotes and slashes with the non-ASCII characters ” and ?.
/// A string that can be used as a filename. If the output string would otherwise be empty, returns "_".
public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true)
{
    StringBuilder sb = new StringBuilder(text.Length);
    var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars());
    bool changed = false;
    for (int i = 0; i < text.Length; i++) {
        char c = text[i];
        if (invalids.Contains(c)) {
            changed = true;
            var repl = replacement ?? '\0';
            if (fancy) {
                if (c == '"')       repl = '”'; // U+201D right double quotation mark
                else if (c == '\'') repl = '’'; // U+2019 right single quotation mark
                else if (c == '/')  repl = '?'; // U+2044 fraction slash
            }
            if (repl != '\0')
                sb.Append(repl);
        } else
            sb.Append(c);
    }
    if (sb.Length == 0)
        return "_";
    return changed ? sb.ToString() : text;
}



5> leggetter..:

迭戈确实有正确的解决方案,但那里有一个非常小的错误.使用的string.Replace的版本应该是string.Replace(char,char),没有string.Replace(char,string)

我无法编辑答案,或者我只是做了一些小改动.

所以它应该是:

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}



6> rkagerer..:

迭戈的回答略有不同.

如果你不害怕Unicode,你可以通过用类似它们的有效Unicode符号替换无效字符来保持更高的保真度.这是我最近涉及木材切割清单的项目中使用的代码:

static string MakeValidFilename(string text) {
  text = text.Replace('\'', '’'); // U+2019 right single quotation mark
  text = text.Replace('"',  '”'); // U+201D right double quotation mark
  text = text.Replace('/', '?');  // U+2044 fraction slash
  foreach (char c in System.IO.Path.GetInvalidFileNameChars()) {
    text = text.Replace(c, '_');
  }
  return text;
}

这会产生类似的文件名1?2” spruce.txt而不是1_2_ spruce.txt

是的,它确实有效:

Explorer示例

买者自负

我知道这个技巧可以在NTFS上运行,但很惊讶它发现它也适用于FAT和FAT32分区.这是因为长文件名都以Unicode格式存储,甚至可以追溯到与Windows 95/NT.我在Win7,XP甚至基于Linux的路由器上进行了测试,他们出现了.对于DOSBox内部不能说相同.

也就是说,在你坚持下去之前,先考虑一下你是否真的需要额外的保真度.Unicode外观可能会混淆人们或旧程序,例如旧操作系统依赖于代码页.



7> DavidG..:

下面是使用公认的答案的一个版本,Linq它的用途Enumerable.Aggregate

string fileName = "something";

Path.GetInvalidFileNameChars()
    .Aggregate(fileName, (current, c) => current.Replace(c, '_'));



8> jnm2..:

这是使用StringBuilderIndexOfAny带有批量附加以提高效率的版本。它还返回原始字符串,而不是创建重复的字符串。

最后但并非最不重要的一点是,它具有switch语句,该语句返回外观相似的字符,您可以根据需要自定义任何方式。查看Unicode.org的易混淆查询,以查看可能有哪些选项,具体取决于字体。

public static string GetSafeFilename(string arbitraryString)
{
    var invalidChars = System.IO.Path.GetInvalidFileNameChars();
    var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0);
    if (replaceIndex == -1) return arbitraryString;

    var r = new StringBuilder();
    var i = 0;

    do
    {
        r.Append(arbitraryString, i, replaceIndex - i);

        switch (arbitraryString[replaceIndex])
        {
            case '"':
                r.Append("''");
                break;
            case '<':
                r.Append('\u02c2'); // '?' (modifier letter left arrowhead)
                break;
            case '>':
                r.Append('\u02c3'); // '?' (modifier letter right arrowhead)
                break;
            case '|':
                r.Append('\u2223'); // '?' (divides)
                break;
            case ':':
                r.Append('-');
                break;
            case '*':
                r.Append('\u2217'); // '?' (asterisk operator)
                break;
            case '\\':
            case '/':
                r.Append('\u2044'); // '?' (fraction slash)
                break;
            case '\0':
            case '\f':
            case '?':
                break;
            case '\t':
            case '\n':
            case '\r':
            case '\v':
                r.Append(' ');
                break;
            default:
                r.Append('_');
                break;
        }

        i = replaceIndex + 1;
        replaceIndex = arbitraryString.IndexOfAny(invalidChars, i);
    } while (replaceIndex != -1);

    r.Append(arbitraryString, i, arbitraryString.Length - i);

    return r.ToString();
}

它不检查...或像保留名称CON,因为它没有明确的更换应该是什么。

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有