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

我用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();

这是可行的,但我相信应该有更简单、更聪明的解决方案。任何想法?

447824 次浏览

Path.GetFileName

返回所表示的文件路径的文件名和扩展名

.

.

.

Path.GetFileNameWithoutExtension

返回不带文件路径扩展名的文件名

.由只读字符跨度表示

Path类非常棒。

你可以像下面这样使用路径 API:

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

更多信息:路径。GetFileNameWithoutExtension

试一试

fileName = Path.GetFileName (path);

http://msdn.microsoft.com/de-de/library/system.io.path.getfilename.aspx < a href = " http://msdn.microsoft.com/de-de/library/system.io.path.getfilename.aspx " > < / >

试试这个:

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

这将为fileName返回“hello”。

试一试

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

var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);

路径。GetFileNameWithoutExtension < / >

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


string FileName = Location.Substring(Location.LastIndexOf('\\') +
1);
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>
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

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

在做了这样的更改之后,要考虑的一件事是改进这段代码所产生的垃圾数量:

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

因此,从样例路径"C:\Program Files\hello.txt"提取基文件名应该会产生(临时的)objects "C:""Program Files""hello.txt""hello""txt"string[3]string[2]。如果在大量路径上调用该方法,这可能很重要。为了改进这一点,我们可以自己搜索path来定位基名的起始点和结束点,并使用它们来创建object1 new object0…

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())之间有一个微妙但重要的区别:前者提取第一个 .之前的所有内容,后者提取GetFileBaseNameUsingSplit()0 .之前的所有内容。这对问题中的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" EXCEPTION:长度不能小于零。(参数的长度)
没有扩展名 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\" EXCEPTION:长度不能小于零。(参数的长度)
目录路径 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);
}
}
}

在一些极端情况下博士TL; 问题中的代码并没有表现出许多人所期望的那样。如果您打算编写自己的路径操作代码,请务必考虑到…

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

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