给定文件系统路径,是不是有更短的方法来提取没有扩展名的文件名?

Posted

技术标签:

【中文标题】给定文件系统路径,是不是有更短的方法来提取没有扩展名的文件名?【英文标题】:Given a filesystem path, is there a shorter way to extract the filename without its extension?给定文件系统路径,是否有更短的方法来提取没有扩展名的文件名? 【发布时间】:2011-10-18 18:20:43 【问题描述】:

我在 WPF C# 中编程。我有例如以下路径:

C:\Program Files\hello.txt

我想从中提取 hello

路径是从数据库中检索到的string。目前我正在使用以下代码将路径拆分为'\',然后再拆分为'.'

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

它有效,但我相信应该有更短、更智能的解决方案。有什么想法吗?

【问题讨论】:

在我的系统中,Path.GetFileName("C:\\dev\\some\\path\\to\\file.cs") 正在返回相同的字符串,并且由于某种原因没有将其转换为“file.cs”。如果我将我的代码复制/粘贴到在线编译器中(如rextester.com),它可以工作...? 【参考方案1】:

Path.GetFileName

返回表示的文件路径的文件名和扩展名 通过只读字符范围。


Path.GetFileNameWithoutExtension

返回不带文件路径扩展名的文件名 由只读字符范围表示。


Path 课程很棒。

【讨论】:

【参考方案2】:

试试

fileName = Path.GetFileName (path);

http://msdn.microsoft.com/de-de/library/system.io.path.getfilename.aspx

【讨论】:

【参考方案3】:

试试

System.IO.Path.GetFileNameWithoutExtension(path); 

演示

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 ''

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

【讨论】:

似乎 Path.GetFileNameWithoutExtension() 不适用于文件扩展名 > 3 个字符。【参考方案4】:

您可以使用Path API 如下:

 var filenNme = Path.GetFileNameWithoutExtension([File Path]);

更多信息:Path.GetFileNameWithoutExtension

【讨论】:

【参考方案5】:
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);

Path.GetFileNameWithoutExtension

【讨论】:

【参考方案6】:

试试这个:

string fileName = Path.GetFileNameWithoutExtension(@"C:\Program Files\hello.txt");

这将为文件名返回“hello”。

【讨论】:

【参考方案7】:
string Location = "C:\\Program Files\\hello.txt";

string FileName = Location.Substring(Location.LastIndexOf('\\') +
    1);

【讨论】:

+1,因为这在作为备份工作的情况下可能会有所帮助,其中文件名在 Path.GetInvalidChars()] 中包含无效字符 [ 等。 在 UNIX ftp 服务器上使用路径时,这实际上非常有用。【参考方案8】:

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

static string GetFileBaseNameUsingSplit(string path)

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

    return fileBaseName;

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

一个string[] 包含一个string 用于path 中的每个路径段 一个string[],在path 的最后一个路径段中,每个. 至少包含一个string

因此,从示例路径"C:\Program Files\hello.txt" 中提取基本文件名应生成(临时)objects "C:""Program Files""hello.txt""hello""txt"、@987654343 @ 和 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;

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

从评论中可以看出,前面的方法是有问题的。虽然假设所有路径都以带有扩展名的文件名结尾,但如果路径以\(即目录路径)结尾或最后一段中不包含扩展名,它将引发异常。为了解决这个问题,我们需要添加一个额外的检查来说明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;

现在这个版本比原来的版本短了很多,但它更有效并且(现在)也正确。

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

Description Method Path Result
Single extension GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt" "hello"
Single extension GetFileBaseNameUsingPath() "C:\Program Files\hello.txt" "hello"
Single extension GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt" "hello"
Single extension GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt" "hello"




Double extension GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt.ext" "hello"
Double extension GetFileBaseNameUsingPath() "C:\Program Files\hello.txt.ext" "hello.txt"
Double extension GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt.ext" "hello"
Double extension GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt.ext" "hello"




No extension GetFileBaseNameUsingSplit() "C:\Program Files\hello" "hello"
No extension GetFileBaseNameUsingPath() "C:\Program Files\hello" "hello"
No extension GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello" EXCEPTION: Length cannot be less than zero. (Parameter 'length')
No extension GetFileBaseNameUsingSubstring() "C:\Program Files\hello" "hello"




Leading period GetFileBaseNameUsingSplit() "C:\Program Files\.hello.txt" ""
Leading period GetFileBaseNameUsingPath() "C:\Program Files\.hello.txt" ".hello"
Leading period GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\.hello.txt" ""
Leading period GetFileBaseNameUsingSubstring() "C:\Program Files\.hello.txt" ""




Trailing period GetFileBaseNameUsingSplit() "C:\Program Files\hello.txt." "hello"
Trailing period GetFileBaseNameUsingPath() "C:\Program Files\hello.txt." "hello.txt"
Trailing period GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\hello.txt." "hello"
Trailing period GetFileBaseNameUsingSubstring() "C:\Program Files\hello.txt." "hello"




Directory path GetFileBaseNameUsingSplit() "C:\Program Files\" ""
Directory path GetFileBaseNameUsingPath() "C:\Program Files\" ""
Directory path GetFileBaseNameUsingSubstringUnsafe() "C:\Program Files\" EXCEPTION: Length cannot be less than zero. (Parameter 'length')
Directory path GetFileBaseNameUsingSubstring() "C:\Program Files\" ""




Current file path GetFileBaseNameUsingSplit() "hello.txt" "hello"
Current file path GetFileBaseNameUsingPath() "hello.txt" "hello"
Current file path GetFileBaseNameUsingSubstringUnsafe() "hello.txt" "hello"
Current file path GetFileBaseNameUsingSubstring() "hello.txt" "hello"




Parent file path GetFileBaseNameUsingSplit() "..\hello.txt" "hello"
Parent file path GetFileBaseNameUsingPath() "..\hello.txt" "hello"
Parent file path GetFileBaseNameUsingSubstringUnsafe() "..\hello.txt" "hello"
Parent file path GetFileBaseNameUsingSubstring() "..\hello.txt" "hello"




Parent directory path GetFileBaseNameUsingSplit() ".." ""
Parent directory path GetFileBaseNameUsingPath() ".." "."
Parent directory path GetFileBaseNameUsingSubstringUnsafe() ".." ""
Parent directory path 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(
                $"ItemLeftPaddingresult.DescriptionItemRightPadding",
                $"ItemLeftPaddingresult.MethodItemRightPadding",
                $"ItemLeftPaddingresult.PathItemRightPadding",
                $"ItemLeftPaddingresult.ResultItemRightPadding"
            );
        

        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);
        
    

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

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

并非所有文件路径都遵循X:\Directory\File.ext的常用公式!

【讨论】:

【参考方案9】:
string filepath = "C:\\Program Files\\example.txt";
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(filepath);
FileInfo fi = new FileInfo(filepath);
Console.WriteLine(fi.Name);

//input to the "fi" is a full path to the file from "filepath"
//This code will return the fileName from the given path

//output
//example.txt

【讨论】:

我很惊讶FileVersionInfo 可以用于没有版本信息的文件。请注意,GetVersionInfo() 只能用于引用已存在文件的路径。虽然任一类都可用于获取文件名,但问题也要求删除扩展名。【参考方案10】:
Namespace: using System.IO;  
 //use this to get file name dynamically 
 string filelocation = Properties.Settings.Default.Filelocation;
//use this to get file name statically 
//string filelocation = @"D:\FileDirectory\";
string[] filesname = Directory.GetFiles(filelocation); //for multiple files
    

如果您要动态获取文件名,请在 App.config 文件中配置路径 -

    <userSettings>
        <ConsoleApplication13.Properties.Settings>
          <setting name="Filelocation" serializeAs="String">
            <value>D:\\DeleteFileTest</value>
          </setting>
              </ConsoleApplication13.Properties.Settings>
      </userSettings>

【讨论】:

问题是如何从文件路径中提取不带扩展名的文件名。相反,这是检索目录的直接子文件,该目录可能由配置文件指定,也可能不指定。这些并不是真正接近同一件事。

以上是关于给定文件系统路径,是不是有更短的方法来提取没有扩展名的文件名?的主要内容,如果未能解决你的问题,请参考以下文章

是否有更短的方法来更新 Oracle SQL 上的范围值列?

有没有比 alloc 和 initWithFormat 更短的方法来从两种不同的数据类型创建 NSString?

如何为嵌套资源丰富的路线制作更短的路径

有没有更短的写 x == y OR x == z 的方法? [复制]

有没有更好的方法以更短的行从网络上抓取 MSFT 数据?我已经尝试过了,但得到的问题是“模块”对象不可调用

textView 动态更改为更短的文本而不是 ellipsize