给定文件系统路径,是不是有更短的方法来提取没有扩展名的文件名?
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"
中提取基本文件名应生成(临时)object
s "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 的方法? [复制]