从C#中的路径字符串中获取文件名

KMC*_*KMC 251 c#

我在WPF C#中编程.我有以下路径:

C:\Program Files\hello.txt
Run Code Online (Sandbox Code Playgroud)

我想从中输出" 你好 ".

该路径是数据库中的字符串提取.目前我正在使用以下方法(从'\'拆分路径然后再用'.'拆分):

string path = "C:\\Program Files\\hello.txt";
string[] pathArr = path.Split('\\');
string[] fileArr = pathArr.Last().Split('.');
string fileName = fileArr.Last().ToString();
Run Code Online (Sandbox Code Playgroud)

它有效,但我相信应该有更短更智能的解决方案.任何的想法?

Mon*_*day 29

尝试

System.IO.Path.GetFileNameWithoutExtension(path); 
Run Code Online (Sandbox Code Playgroud)

演示

string fileName = @"C:\mydir\myfile.ext";
string path = @"C:\mydir\";
string result;

result = Path.GetFileNameWithoutExtension(fileName);
Console.WriteLine("GetFileNameWithoutExtension('{0}') returns '{1}'", 
    fileName, result);

result = Path.GetFileName(path);
Console.WriteLine("GetFileName('{0}') returns '{1}'", 
    path, result);

// This code produces output similar to the following:
//
// GetFileNameWithoutExtension('C:\mydir\myfile.ext') returns 'myfile'
// GetFileName('C:\mydir\') returns ''
Run Code Online (Sandbox Code Playgroud)

https://msdn.microsoft.com/en-gb/library/system.io.path.getfilenamewithoutextension%28v=vs.80%29.aspx


Pey*_*man 25

您可以使用Path API,如下所示:

 var filenNme = Path.GetFileNameWithoutExtension([File Path]);
Run Code Online (Sandbox Code Playgroud)

更多信息:Path.GetFileNameWithoutExtension


Hol*_*eam 19

var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
Run Code Online (Sandbox Code Playgroud)

Path.GetFileNameWithoutExtension


Tim*_*Tim 11

试试这个:

string fileName = Path.GetFileNameWithoutExtension(@"C:\Program Files\hello.txt");
Run Code Online (Sandbox Code Playgroud)

这将为fileName返回"hello".


小智 9

string Location = "C:\\Program Files\\hello.txt";

string FileName = Location.Substring(Location.LastIndexOf('\\') +
    1);
Run Code Online (Sandbox Code Playgroud)


Sum*_*nth 6

试试这个,

string FilePath=@"C:\mydir\myfile.ext";
string Result=Path.GetFileName(FilePath);//With Extension
string Result=Path.GetFileNameWithoutExtension(FilePath);//Without Extension
Run Code Online (Sandbox Code Playgroud)

  • 那么最高投票的答案就是这么说的? (2认同)

BAC*_*CON 6

首先,问题中的代码不会产生所描述的输出。它提取文件扩展名( "txt") 而不是文件基本名称( "hello")。要做到这一点,最后一行应该调用First(),而不是Last(),像这样......

static string GetFileBaseNameUsingSplit(string path)
{
    string[] pathArr = path.Split('\\');
    string[] fileArr = pathArr.Last().Split('.');
    string fileBaseName = fileArr.First().ToString();

    return fileBaseName;
}
Run Code Online (Sandbox Code Playgroud)

进行更改后,就改进此代码而言,要考虑的一件事是它创建的垃圾量:

  • Astring[]中string的每个路径段包含一个path
  • A中的最后一个路径段中的每个string[]包含至少一个string.path

因此,从示例路径中提取基本文件名"C:\Program Files\hello.txt"应生成(临时)objects "C:"、"Program Files"、"hello.txt"、"hello"、"txt"、 astring[3]和 a string[2]。如果在大量路径上调用该方法,这可能很重要。为了改善这一点,我们可以path自己搜索以定位基本名称的起点和终点,并使用它们来创建一个新的string...

static string GetFileBaseNameUsingSubstringUnsafe(string path)
{
    // Fails on paths with no file extension - DO NOT USE!!
    int startIndex = path.LastIndexOf('\\') + 1;
    int endIndex = path.IndexOf('.', startIndex);
    string fileBaseName = path.Substring(startIndex, endIndex - startIndex);

    return fileBaseName;
}
Run Code Online (Sandbox Code Playgroud)

这是使用最后一个字符的索引\作为基本名称的开始,并从那里寻找第一个.用作基本名称结束后字符的索引。这比原始代码短吗?不完全的。这是一个“更聪明”的解决方案吗?我想是这样。至少,如果不是因为……

从评论中可以看出,之前的方法是有问题的。尽管假设所有路径都以带扩展名的文件名结尾,但如果路径以\(即目录路径)结尾或在最后一段中不包含扩展名,它将抛出异常。为了解决这个问题,我们需要额外的检查添加到账户时,endIndex是-1(即.未找到)...

static string GetFileBaseNameUsingSubstring(string path)
{
    int startIndex = path.LastIndexOf('\\') + 1;
    int endIndex = path.IndexOf('.', startIndex);
    int length = (endIndex >= 0 ? endIndex : path.Length) - startIndex;
    string fileBaseName = path.Substring(startIndex, length);

    return fileBaseName;
}
Run Code Online (Sandbox Code Playgroud)

现在这个版本远不及原始版本,但它更高效,(现在)也正确。

至于实现此功能的 .NET 方法,许多其他答案建议使用Path.GetFileNameWithoutExtension(),这是一个显而易见的简单解决方案,但不会产生与问题中的代码相同的结果。GetFileBaseNameUsingSplit()和Path.GetFileNameWithoutExtension()(GetFileBaseNameUsingPath()下面)之间有一个微妙但重要的区别:前者提取第一个 之前的所有内容.,后者提取最后一个 之前的所有内容.。这path对问题中的示例没有影响,但请看一下这张表,比较了使用各种路径调用时上述四种方法的结果...

描述 方法 小路 结果
单分机 GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt" "hello"
单分机 GetFileBaseNameUsingPath() "C:\Program Files\hello.txt" "hello"
单分机 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt" "hello"
单分机 GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt" "hello"




双分机 GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt.ext" "hello"
双分机 GetFileBaseNameUsingPath() "C:\Program Files\hello.txt.ext" "hello.txt"
双分机 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt.ext" "hello"
双分机 GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt.ext" "hello"




无延期 GetFileBaseNameUsingSplit() "C:\Program Files\hello" "hello"
无延期 GetFileBaseNameUsingPath() "C:\Program Files\hello" "hello"
无延期 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello" 例外:长度不能小于零。(参数'长度')
无延期 GetFileBaseNameUsingSubstring() "C:\Program Files\hello" "hello"




领先期 GetFileBaseNameUsingSplit() "C:\Program Files\.hello.txt" ""
领先期 GetFileBaseNameUsingPath() "C:\Program Files\.hello.txt" ".hello"
领先期 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\.hello.txt" ""
领先期 GetFileBaseNameUsingSubstring() "C:\Program Files\.hello.txt" ""




追踪期 GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt." "hello"
追踪期 GetFileBaseNameUsingPath() "C:\Program Files\hello.txt." "hello.txt"
追踪期 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt." "hello"
追踪期 GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt." "hello"




目录路径 GetFileBaseNameUsingSplit() "C:\Program Files\" ""
目录路径 GetFileBaseNameUsingPath() "C:\Program Files\" ""
目录路径 GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\" 例外:长度不能小于零。(参数'长度')
目录路径 GetFileBaseNameUsingSubstring() "C:\Program Files\" ""




当前文件路径 GetFileBaseNameUsingSplit() "hello.txt" "hello"
当前文件路径 GetFileBaseNameUsingPath() "hello.txt" "hello"
当前文件路径 GetFileBaseNameUsingSubstringUnsafe() "hello.txt" "hello"
当前文件路径 GetFileBaseNameUsingSubstring() "hello.txt" "hello"




父文件路径 GetFileBaseNameUsingSplit() "..\hello.txt" "hello"
父文件路径 GetFileBaseNameUsingPath() "..\hello.txt" "hello"
父文件路径 GetFileBaseNameUsingSubstringUnsafe() "..\hello.txt" "hello"
父文件路径 GetFileBaseNameUsingSubstring() "..\hello.txt" "hello"




父目录路径 GetFileBaseNameUsingSplit() ".." ""
父目录路径 GetFileBaseNameUsingPath() ".." "."
父目录路径 GetFileBaseNameUsingSubstringUnsafe() ".." ""
父目录路径 GetFileBaseNameUsingSubstring() ".." ""

...并且您会看到,Path.GetFileNameWithoutExtension()当传递文件名具有双扩展名或前导和/或尾随的路径时,会产生不同的结果.。您可以使用以下代码自己尝试...

using System;
using System.IO;
using System.Linq;
using System.Reflection;

namespace SO6921105
{
    internal class PathExtractionResult
    {
        public string Description { get; set; }
        public string Method { get; set; }
        public string Path { get; set; }
        public string Result { get; set; }
    }

    public static class Program
    {
        private static string GetFileBaseNameUsingSplit(string path)
        {
            string[] pathArr = path.Split('\\');
            string[] fileArr = pathArr.Last().Split('.');
            string fileBaseName = fileArr.First().ToString();

            return fileBaseName;
        }

        private static string GetFileBaseNameUsingPath(string path)
        {
            return Path.GetFileNameWithoutExtension(path);
        }

        private static string GetFileBaseNameUsingSubstringUnsafe(string path)
        {
            // Fails on paths with no file extension - DO NOT USE!!
            int startIndex = path.LastIndexOf('\\') + 1;
            int endIndex = path.IndexOf('.', startIndex);
            string fileBaseName = path.Substring(startIndex, endIndex - startIndex);

            return fileBaseName;
        }

        private static string GetFileBaseNameUsingSubstring(string path)
        {
            int startIndex = path.LastIndexOf('\\') + 1;
            int endIndex = path.IndexOf('.', startIndex);
            int length = (endIndex >= 0 ? endIndex : path.Length) - startIndex;
            string fileBaseName = path.Substring(startIndex, length);

            return fileBaseName;
        }

        public static void Main()
        {
            MethodInfo[] testMethods = typeof(Program).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
                .Where(method => method.Name.StartsWith("GetFileBaseName"))
                .ToArray();
            var inputs = new[] {
                new { Description = "Single extension",      Path = @"C:\Program Files\hello.txt"     },
                new { Description = "Double extension",      Path = @"C:\Program Files\hello.txt.ext" },
                new { Description = "No extension",          Path = @"C:\Program Files\hello"         },
                new { Description = "Leading period",        Path = @"C:\Program Files\.hello.txt"    },
                new { Description = "Trailing period",       Path = @"C:\Program Files\hello.txt."    },
                new { Description = "Directory path",        Path = @"C:\Program Files\"              },
                new { Description = "Current file path",     Path = "hello.txt"                       },
                new { Description = "Parent file path",      Path = @"..\hello.txt"                   },
                new { Description = "Parent directory path", Path = ".."                              }
            };
            PathExtractionResult[] results = inputs
                .SelectMany(
                    input => testMethods.Select(
                        method => {
                            string result;

                            try
                            {
                                string returnValue = (string) method.Invoke(null, new object[] { input.Path });

                                result = $"\"{returnValue}\"";
                            }
                            catch (Exception ex)
                            {
                                if (ex is TargetInvocationException)
                                    ex = ex.InnerException;
                                result = $"EXCEPTION: {ex.Message}";
                            }

                            return new PathExtractionResult() {
                                Description = input.Description,
                                Method = $"{method.Name}()",
                                Path = $"\"{input.Path}\"",
                                Result = result
                            };
                        }
                    )
                ).ToArray();
            const int ColumnPadding = 2;
            ResultWriter writer = new ResultWriter(Console.Out) {
                DescriptionColumnWidth = results.Max(output => output.Description.Length) + ColumnPadding,
                MethodColumnWidth = results.Max(output => output.Method.Length) + ColumnPadding,
                PathColumnWidth = results.Max(output => output.Path.Length) + ColumnPadding,
                ResultColumnWidth = results.Max(output => output.Result.Length) + ColumnPadding,
                ItemLeftPadding = " ",
                ItemRightPadding = " "
            };
            PathExtractionResult header = new PathExtractionResult() {
                Description = nameof(PathExtractionResult.Description),
                Method = nameof(PathExtractionResult.Method),
                Path = nameof(PathExtractionResult.Path),
                Result = nameof(PathExtractionResult.Result)
            };

            writer.WriteResult(header);
            writer.WriteDivider();
            foreach (IGrouping<string, PathExtractionResult> resultGroup in results.GroupBy(result => result.Description))
            {
                foreach (PathExtractionResult result in resultGroup)
                    writer.WriteResult(result);
                writer.WriteDivider();
            }
        }
    }

    internal class ResultWriter
    {
        private const char DividerChar = '-';
        private const char SeparatorChar = '|';

        private TextWriter Writer { get; }

        public ResultWriter(TextWriter writer)
        {
            Writer = writer ?? throw new ArgumentNullException(nameof(writer));
        }

        public int DescriptionColumnWidth { get; set; }

        public int MethodColumnWidth { get; set; }

        public int PathColumnWidth { get; set; }

        public int ResultColumnWidth { get; set; }

        public string ItemLeftPadding { get; set; }

        public string ItemRightPadding { get; set; }

        public void WriteResult(PathExtractionResult result)
        {
            WriteLine(
                $"{ItemLeftPadding}{result.Description}{ItemRightPadding}",
                $"{ItemLeftPadding}{result.Method}{ItemRightPadding}",
                $"{ItemLeftPadding}{result.Path}{ItemRightPadding}",
                $"{ItemLeftPadding}{result.Result}{ItemRightPadding}"
            );
        }

        public void WriteDivider()
        {
            WriteLine(
                new string(DividerChar, DescriptionColumnWidth),
                new string(DividerChar, MethodColumnWidth),
                new string(DividerChar, PathColumnWidth),
                new string(DividerChar, ResultColumnWidth)
            );
        }

        private void WriteLine(string description, string method, string path, string result)
        {
            Writer.Write(SeparatorChar);
            Writer.Write(description.PadRight(DescriptionColumnWidth));
            Writer.Write(SeparatorChar);
            Writer.Write(method.PadRight(MethodColumnWidth));
            Writer.Write(SeparatorChar);
            Writer.Write(path.PadRight(PathColumnWidth));
            Writer.Write(SeparatorChar);
            Writer.Write(result.PadRight(ResultColumnWidth));
            Writer.WriteLine(SeparatorChar);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

TL; DR 问题中的代码在某些极端情况下的行为不像许多人所期望的那样。如果您要编写自己的路径操作代码,请务必考虑...

  • ...如何定义“没有扩展名的文件名”(是第一个.之前的所有内容还是最后一个之前的所有内容.?)
  • ...具有多个扩展名的文件
  • ...没有扩展名的文件
  • ...带有前导的文件 .
  • ...带有尾随的文件.(可能不会在 Windows 上遇到,但它们是可能的)
  • ...带有“扩展名”的目录或包含 .
  • ...以 a 结尾的路径 \
  • ...相对路径

并非所有文件路径都遵循X:\Directory\File.ext!