我需要在C#中处理一些可能包含非法字符的文件路径,例如:
C:\path\something\output_at_13:26:43.txt
在该路径中,时间戳记中的:
使文件名无效,我想用另一个安全字符替换它们。
我已经在此处搜索有关SO的解决方案,但它们似乎都基于以下内容:
path = string.Join("_", path.Split(Path.GetInvalidFileNameChars()));
或类似的解决方案。但是,这些解决方案不是很好,因为它们弄乱了驱动器号,并且我得到了以下输出:
C_\path\something\output_at_13_26_43.txt
我尝试使用Path.GetInvalidPathChars()
,但是它仍然不起作用,因为它在非法字符中不包含:
,因此它不能替换文件名中的那些字符。
所以,在弄清楚之后,我尝试这样做:
string dir = Path.GetDirectoryName(path);
string file = Path.GetFileName(path);
file = string.Join(replacement, file.Split(Path.GetInvalidFileNameChars()));
dir = string.Join(replacement, dir.Split(Path.GetInvalidPathChars()));
path = Path.Combine(dir, file);
但这也不好,因为文件名中的:
似乎会干扰Path.GetFilename()
逻辑,并且它仅返回最后一个:
之后的最后一个,因此我正在迷失道路。
如何在没有hacky解决方案的情况下“正确”执行此操作?
答案 0 :(得分:2)
您可以编写一个简单的消毒剂,对每个字符进行迭代,并知道何时将冒号用作驱动器分隔符。这将捕获字母A-Z的任意组合,后接直接“:”。它还将检测路径分隔符而不逃逸它们。它不会在输入字符串的开头检测到空格,因此,如果您的输入数据可能随附在其中,则必须先对其进行修剪或相应地修改消毒剂:
enum ParserState {
PossibleDriveLetter,
PossibleDriveLetterSeparator,
Path
}
static string SanitizeFileName(string input) {
StringBuilder output = new StringBuilder(input.Length);
ParserState state = ParserState.PossibleDriveLetter;
foreach(char current in input) {
if (((current >= 'a') && (current <= 'z')) || ((current >= 'A') && (current <= 'Z'))) {
output.Append(current);
if (state == ParserState.PossibleDriveLetter) {
state = ParserState.PossibleDriveLetterSeparator;
}
else {
state = ParserState.Path;
}
}
else if ((current == Path.DirectorySeparatorChar) ||
(current == Path.AltDirectorySeparatorChar) ||
((current == ':') && (state == ParserState.PossibleDriveLetterSeparator)) ||
!Path.GetInvalidFileNameChars().Contains(current)) {
output.Append(current);
state = ParserState.Path;
}
else {
output.Append('_');
state = ParserState.Path;
}
}
return output.ToString();
}
您可以try it out here。
答案 1 :(得分:1)
您绝对应该确保您仅收到有效的文件名。
如果不能,并且确定目录名称将是,则可以将路径拆分为最后一个反斜杠(假设使用Windows)并重新组装字符串:
public static string SanitizePath(string path)
{
var lastBackslash = path.LastIndexOf('\\');
var dir = path.Substring(0, lastBackslash);
var file = path.Substring(lastBackslash, path.Length - lastBackslash);
foreach (var invalid in Path.GetInvalidFileNameChars())
{
file = file.Replace(invalid, '_');
}
return dir + file;
}