C#如何更改相对或绝对URI的文件名

3
我希望你能为绝对或相对uri的文件名更改找到一种简洁的方法,可能包含多个片段。我们事先不知道它是否是绝对或相对的,因此需要检测:
以下是测试案例:
    [Test]
    public void Can_change_path_file_name()
    {
        Fix("file.txt").ShouldEqual("file_fixed.txt");
        Fix("/file.txt").ShouldEqual("/file_fixed.txt");
        Fix("directory/file.txt").ShouldEqual("directory/file_fixed.txt");
        Fix("/directory/file.txt").ShouldEqual("/directory/file_fixed.txt");
        Fix("/directory/subdirectory/file.txt").ShouldEqual("/directory/subdirectory/file_fixed.txt");
        Fix("http://www.test.com/directory/subdirectory/file.txt").ShouldEqual("http://www.test.com/directory/subdirectory/file_fixed.txt");
        Fix("/directory/file/file.txt").ShouldEqual("/directory/file/file_fixed.txt");
    }

    private string Fix(string uri)
    {
       // fill me with goodness
    }

我的解决方案可行,但似乎有点复杂。我在下面发布了它,以便您可以改进它:

private string Fix(string uri)
{
    var fileName = Path.GetFileNameWithoutExtension(uri);
    var extension = Path.GetExtension(uri);
    fileName += "_fixed" + extension;

    var path = uri.Contains('/') ? uri.Substring(0, uri.LastIndexOf('/') + 1) : "";
    return Combine(path, fileName);
}

private string Combine(string path1, string path2)
{
    if (path1 == null)
    {
        throw new ArgumentNullException("path1");
    }

    if (path2 == null)
    {
        throw new ArgumentNullException("path2");
    }

    if (String.IsNullOrEmpty(path2))
    {
        return path1;
    }

    if (String.IsNullOrEmpty(path1))
    {
        return path2;
    }

    if (path2.StartsWith("http://") || path2.StartsWith("https://"))
    {
        return path2;
    }

    var ch = path1[path1.Length - 1];

    if (ch != '/')
    {
        return (path1.TrimEnd('/') + '/' + path2.TrimStart('/'));
    }

    return (path1 + path2);
}
4个回答

4
没有正则表达式,也没有字符串索引。
只需使用 .NET 的 Path 方法来检索和重组新文件名:
/// <summary>
/// Partner to Path.ChangeExtension. This function changes the base filename portion
/// </summary>
/// <param name="path"></param>
/// <param name="newFilename"></param>
/// <returns></returns>
public static String ChangeFilename(String path, String newFilename)
{
   String directoryName = Path.GetDirectoryName(path); //e.g. "C:\Temp\foo.dat" ==> "C:\Temp"
   //String oldFilename = Path.GetFileName(path); //e.g. "C:\Temp\foo.dat" ==> "foo.dat"
   //String filenameWithoutExtension = Path.GetFileNameWithoutExtension(path); //e.g. "C:\Temp\foo.dat" ==> "foo"
   String extension = Path.GetExtension(path); //e.g. "C:\Temp\foo.dat" ==> ".dat"

   //Reassemble as
   //    directoryName \ newFilename dotExtension
   return String.Format("{0}{1}{2}{3}",
         directoryName, 
         Path.DirectorySeparatorChar,
         newFilename,
         extension);
}

注意:所有代码均已发布到公共领域,不需要归属声明。


3

为什么不能简单地使用字符串替换呢?

private string Fix(string uri)
{
    var fileName = Path.GetFileNameWithoutExtension(uri);
    var extension = Path.GetExtension(uri);

    return uri.Replace(string.Format("{0}{1}", fileName, extension), string.Format("{0}_fixed{1}", fileName, extension));
}

如果您的文件名也出现在URI的其他部分中,那么这种情况只会出错。

另一种没有这个缺点的选择是:

private string Fix(string uri)
    {
        var fileName = Path.GetFileNameWithoutExtension(uri);
        var extension = Path.GetExtension(uri);
        var slashIndex = uri.LastIndexOf("/");

        return string.Format("{0}{1}_fixed{2}", uri.Substring(0, slashIndex + 1), fileName, extension);
    }

@SLaks - 这是一个正则表达式吗?你有+2,所以我认为它是有用的东西? - Ben Foster
@SLaks - 是的,这就是我说在那种情况下会出错的原因。也许 OP 事先知道这种情况会发生。 - Carvellis
@Ben:这只是一个示例路径。我指出了Quimcia刚提到的缺点。 - SLaks
+1 - 当然没问题。它还可以处理没有扩展名的文件名,这很好。 - Ben Foster
1
顺便说一下,你需要从fixed.{2}中移除".",因为GetExtension方法已经包含了"."。 - Ben Foster
显示剩余2条评论

1

要不要使用一些正则表达式呢?

\b[a-zA-Z0-9]+\.[a-zA-Z0-9]+$

这应该可以找到所有以扩展名结尾的文件

接下来,如果你捕获了文件...

\b([a-zA-Z0-9]+)(\.[a-zA-Z0-9]+)$

...然后你可以替换它:

var result = Regex.Replace( 
    input,
    @"\b([a-zA-Z0-9]+)(\.[a-zA-Z0-9]+)$",
    "$1_fixed$2" );

完成了。在编写代码之前,您可以使用在线正则表达式测试工具(比如这个)进行测试。


1
我事先不知道文件名。本质上,我需要在文件名的末尾(扩展名之前)添加一些文本。 - Ben Foster
@Ben - 我调整了我的示例。 - Uwe Keim
1
我已经更新了我的测试,包括一个用于重复目录/文件段的测试。你的代码通过了+1。 - Ben Foster

1

我已经将可行的解决方案封装成一个实用方法。对其他人应该有所帮助。

    /// <summary>
    /// Changes the file name of the <paramref name="uri"/> using the given <paramref name="modifier"/>
    /// </summary>
    /// <param name="uri">A relative or absolute uri</param>
    /// <param name="modifier">A function to apply to the filename</param>
    /// <returns>The modified uri</returns>
    public static string ModifyUriFileName(string uri, Func<string, string> modifier)
    {
        if (string.IsNullOrEmpty(uri))
        {
            throw new ArgumentNullException("uri");
        }

        var fileName = Path.GetFileNameWithoutExtension(uri);
        var extension = Path.GetExtension(uri);
        var path = uri.Substring(0, uri.LastIndexOf('/') + 1);

        return string.Format("{0}{1}{2}", path, modifier(fileName), extension);
    }

用法: < p > < code > 返回 CommonUtils.ModifyUriFileName(uri,s => s + "_fixed");

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