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


260

我在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)中,则可以正常工作...?
jbyrd

Answers:




29

尝试

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/zh-CN/library/system.io.path.getfilenamewithoutextension%28v=vs.80%29.aspx


似乎Path.GetFileNameWithoutExtension()无法使用文件扩展名> 3个字符。
—NolmëInformatique



11

试试这个:

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

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


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

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

1
+1,因为这在其中备份作为备份(文件名在Path.GetInvalidChars()中包含无效字符[<,>等)的情况下可能很有用。
bhuvin

在UNIX ftp服务器上使用路径时,这实际上非常有用。
s952163

6

试试这个,

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

2
您使用的投票方法完全相同。
CodeCaster

1
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()只能在引用已存在文件的路径上使用。虽然可以使用任何一个类来获取文件名,但该问题也要求删除扩展名。
培根

1

首先,问题中的代码不会产生描述的输出。它提取文件扩展名"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;
}

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

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

因此,从样品中提取路径基本文件名"C:\Program Files\hello.txt"应产生(临时)object小号"C:""Program Files""hello.txt""hello""txt",一个string[3]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 GetFileBaseNameUsingSubstringSafe(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()以下)之间有一个细微但重要的区别:前者在第一个 之前提取所有内容.,而后者在最后一个 之前提取所有内容.。这对于问题中的示例没有什么影响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      | GetFileBaseNameUsingSubstringSafe()   | "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      | GetFileBaseNameUsingSubstringSafe()   | "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          | GetFileBaseNameUsingSubstringSafe()   | "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        | GetFileBaseNameUsingSubstringSafe()   | "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       | GetFileBaseNameUsingSubstringSafe()   | "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        | GetFileBaseNameUsingSubstringSafe()   | "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     | GetFileBaseNameUsingSubstringSafe()   | "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      | GetFileBaseNameUsingSubstringSafe()   | "..\hello.txt"                   | "hello"                                                          |
|-----------------------|---------------------------------------|----------------------------------|------------------------------------------------------------------|
| Parent directory path | GetFileBaseNameUsingSplit()           | ".."                             | ""                                                               |
| Parent directory path | GetFileBaseNameUsingPath()            | ".."                             | "."                                                              |
| Parent directory path | GetFileBaseNameUsingSubstringUnsafe() | ".."                             | ""                                                               |
| Parent directory path | GetFileBaseNameUsingSubstringSafe()   | ".."                             | ""                                                               |
|-----------------------|---------------------------------------|----------------------------------|------------------------------------------------------------------|

...并且您会看到,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 GetFileBaseNameUsingSubstringSafe(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);
        }
    }
}

TL; DR 问题中的代码在某些特殊情况下的行为似乎并不理想。如果要编写自己的路径操作代码,请务必考虑...

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

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


0
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

Your path configuration in App.config file if you are going to get file name dynamically  -

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

问题是询问如何从文件路径中提取不带扩展名的文件名。相反,这正在检索配置文件可能指定或可能未指定的目录的直接子文件。那些不是真的接近同一件事。
培根
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.