递归遍历驱动器并替换非法字符

3
我需要创建一个应用程序,它可以进入特定驱动器,读取所有文件名并将非法的SharePoint字符替换为下划线。我所指的非法字符是:~ # % & * {} / \ | : <> ? - "" 有没有人能提供代码链接或者代码本身来实现这个功能呢?我对C#非常陌生,需要尽可能多的帮助。我已经研究了递归遍历驱动器的代码,但我不确定如何将字符替换和递归循环结合起来。请帮忙!

1
[1] 当你说“替换”时,你是指重命名文件吗? [2] 如果你有能够简单列出所有文件的代码,那么你已经接近成功了:编辑你的问题并添加代码。然后就很容易向你展示该怎么做了。 - egrunin
我在这里创建了一个新问题: http://stackoverflow.com/questions/3015965/changing-filenames-using-regex-and-recursion - yeahumok
4个回答

6

去除非法字符的建议在这里:

如何从路径和文件名中删除非法字符?

您只需要将字符集更改为要删除的字符集。

如果您已经找到了如何递归文件夹,您可以使用以下方式获取每个文件夹中的所有文件:

var files = System.IO.Directory.EnumerateFiles(currentPath);

然后

foreach (string file in files)
{
    System.IO.File.Move(file, ConvertFileName(file));
}

您将编写的ConvertFileName方法接受文件名作为字符串,并返回去除不良字符的文件名。
请注意,如果您使用的是.NET 3.5,则GetFiles()也可以使用。根据MSDN的说法:
EnumerateFiles和GetFiles方法的区别如下:当您使用EnumerateFiles时,您可以在整个集合返回之前开始枚举名称;当您使用GetFiles时,必须等待返回整个名称数组后才能访问该数组。因此,在处理许多文件和目录时,EnumerateFiles可能更有效。
如何递归列出目录
string path = @"c:\dev";
string searchPattern = "*.*";

string[] dirNameArray = Directory.GetDirectories(path, searchPattern, SearchOption.AllDirectories);

// Or, for better performance:
// (but breaks if you don't have access to a sub directory; see 2nd link below)
IEnumerable<string> dirNameEnumeration = Directory.EnumerateDirectories(path, searchPattern, SearchOption.AllDirectories);

3
使用SPUrlUtility.IsLegalCharInUrl(char character)来确定一个非法的“SharePoint”文件字符。 - Stefan
1
@Jared:那些枚举方法是新的,我想是在.NET 4中引入的。正如你所想象的那样,它们返回IEnumerable而不是某种列表。 - Nelson Rothermel

6

虽然不是答案,但请考虑以下两点:

以下字符在文件名中无效,所以您无需担心它们:/\:*?"<>|

确保您的算法适当地处理重复名称。例如,My~Project.docMy#Project.doc都将被重命名为My_Project.doc


2

您需要的是一个递归方法来重命名文件夹中的文件。只需传递根文件夹,它将为所有找到的子文件夹调用自身。

private void SharePointSanitize(string _folder)
{
    // Process files in the directory
    string [] files = Directory.GetFiles(_folder);
    foreach(string fileName in files)
    {
        File.Move(fileName, SharePointRename(fileName));
    }
    string[] folders = Directory.GetDirectories(_folder);
    foreach(string folderName in folders)
    {
        SharePointSanitize(folderName);
    }
}

private string SharePointRename(string _name)
{
    string newName = _name;
    newName = newName.Replace('~', '');
    newName = newName.Replace('#', '');
    newName = newName.Replace('%', '');
    newName = newName.Replace('&', '');
    newName = newName.Replace('*', '');
    newName = newName.Replace('{', '');
    newName = newName.Replace('}', '');
    // .. and so on
    return newName;
}

注意事项:

  1. 您可以将SharePointRename()方法中的''替换为您想要替换的任何字符,例如下划线。
  2. 此方法不会检查两个文件名是否相似,例如thing~和thing%。

感谢 Steven(+1)在我的笔记#2中指出了重复文件问题。 - JYelton
或者创建一个数组:char[] invalidList = new char[] { '~', '#', ... },并使用循环进行替换:foreach (char invalid in invalidList) { newName = newName.Replace(invalid, '_'); } 但是,由于字符串是不可变的,因此每次都必须创建一个新的字符串。也许正则表达式会更快,因为这个原因? - Nelson Rothermel

1
class Program
{
    private static Regex _pattern = new Regex("[~#%&*{}/\\|:<>?\"-]+");
    static void Main(string[] args)
    {
        DirectoryInfo di = new DirectoryInfo("C:\\");
        RecursivelyRenameFilesIn(di);
    }

    public static void RecursivelyRenameFilesIn(DirectoryInfo root)
    {
        foreach (FileInfo fi in root.GetFiles())
            if (_pattern.IsMatch(fi.Name))
                fi.MoveTo(string.Format("{0}\\{1}", fi.Directory.FullName, Regex.Replace(fi.Name, _pattern.ToString(), "_")));

        foreach (DirectoryInfo di in root.GetDirectories())
            RecursivelyRenameFilesIn(di);
    }
}

虽然如史蒂文所指出的那样,这并不能处理重复的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接