Biorąc pod uwagę ścieżkę systemu plików, czy istnieje krótszy sposób na wyodrębnienie nazwy pliku bez rozszerzenia?
Programuję w WPF C#. Mam np. następującą ścieżkę:
C:\Program Files\hello.txt
And I want to extract hello
od tego.
Ścieżka jest string
pobierana z bazy danych. Obecnie używam poniższego kodu, aby podzielić ścieżkę przez '\'
, a następnie ponownie podzielić przez '.'
:
string path = "C:\\Program Files\\hello.txt";
string[] pathArr = path.Split('\\');
string[] fileArr = pathArr.Last().Split('.');
string fileName = fileArr.Last().ToString();
To działa, ale uważam, że powinno być na to krótsze i mądrzejsze rozwiązanie. Jakiś pomysł? 11 answers
/ align = "left" / GetFileName
/ align = "left" / GetFileNameWithoutExtension
Klasa ścieżka jest wspaniała.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-19 07:14:44
Try
fileName = Path.GetFileName (path);
Http://msdn.microsoft.com/de-de/library/system.io.path.getfilename.aspx
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 02:48:58
Try
System.IO.Path.GetFileNameWithoutExtension(path);
Demo
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 ''
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 13:55:21
Możesz użyć Path API w następujący sposób:
var filenNme = Path.GetFileNameWithoutExtension([File Path]);
Więcej informacji: ścieżka.GetFileNameWithoutExtension
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-01 07:29:52
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 02:50:22
Spróbuj tego:
string fileName = Path.GetFileNameWithoutExtension(@"C:\Program Files\hello.txt");
Zwróci "hello" dla nazwy pliku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 02:49:49
string Location = "C:\\Program Files\\hello.txt";
string FileName = Location.Substring(Location.LastIndexOf('\\') +
1);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-27 13:25:51
Spróbuj tego,
string FilePath=@"C:\mydir\myfile.ext";
string Result=Path.GetFileName(FilePath);//With Extension
string Result=Path.GetFileNameWithoutExtension(FilePath);//Without Extension
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-27 07:37:02
Po pierwsze, kod w pytaniu nie daje opisanego wyjścia. Wyciąga rozszerzenie pliku ("txt"
) a nie nazwa pliku ("hello"
). Aby to zrobić, ostatnia linia powinna wywołać First()
, a nie Last()
, w ten sposób...
static string GetFileBaseNameUsingSplit(string path)
{
string[] pathArr = path.Split('\\');
string[] fileArr = pathArr.Last().Split('.');
string fileBaseName = fileArr.First().ToString();
return fileBaseName;
}
Po dokonaniu tej zmiany, jedną rzeczą, o której należy pomyśleć, jeśli chodzi o ulepszenie tego kodu, jest ilość śmieci, które tworzy: {159]}
- a
string[]
zawierający po jednymstring
dla każdego segmentu ścieżki wpath
- A
string[]
zawiera co najmniej jedenstring
dla każdego.
w ostatnim segmencie ścieżki wpath
Dlatego wyodrębnienie nazwy pliku bazowego ze ścieżki próbki "C:\Program Files\hello.txt"
powinno wytworzyć (tymczasowy) object
s "C:"
, "Program Files"
, "hello.txt"
, "hello"
, "txt"
, a string[3]
i a string[2]
. Może to być istotne, jeśli metoda jest wywoływana na dużej liczbie ścieżek. Aby to poprawić, możemy przeszukać path
sami, aby zlokalizować punkty początkowe i końcowe nazwy bazy i użyć ich do utworzenia jednego Nowy 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;
}
To użycie indeksu znaku po ostatnim \
jako początku nazwy bazowej, a stamtąd szukanie pierwszego .
do użycia jako indeksu znaku po końcu nazwy bazowej. Jest krótszy od oryginalnego kodu? Niezupełnie. Czy jest to" mądrzejsze " rozwiązanie? Tak myślę. Przynajmniej tak by było, gdyby nie fakt, że...
Jak widać z komentarza, poprzednia metoda jest problematyczna. Chociaż to działa, jeśli Załóżmy, że wszystkie ścieżki kończą się nazwą pliku z rozszerzeniem, to rzuci wyjątek, jeśli ścieżka kończy się \
(tzn. ścieżką do katalogu) lub w inny sposób nie zawiera rozszerzenia w ostatnim segmencie. Aby to naprawić, musimy dodać dodatkowe sprawdzenie do konta, gdy endIndex
jest -1
(tzn. .
nie został znaleziony)...
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;
}
Teraz ta wersja nie jest krótsza niż oryginał, ale jest bardziej wydajna i (teraz) poprawna.
Jeśli chodzi o metody. NET, które implementują to funkcjonalności, wiele innych odpowiedzi sugeruje użycie Path.GetFileNameWithoutExtension()
, co jest oczywistym, łatwym rozwiązaniem, ale nie daje takich samych wyników jak kod w pytaniu. Istnieje subtelna, ale ważna różnica między GetFileBaseNameUsingSplit()
aPath.GetFileNameWithoutExtension()
(GetFileBaseNameUsingPath()
poniżej): pierwszy wyciąga wszystko przed pierwszy .
i ten ostatni wyciąga wszystko przed ostatni .
. To nie robi różnicy dla próbki path
w pytaniu, ale weź spójrz na tabelę porównującą wyniki powyższych czterech metod wywołanych różnymi ścieżkami...
opis | metoda | ścieżka | wynik |
---|---|---|---|
pojedyncze rozszerzenie | GetFileBaseNameUsingSplit() |
"C:\Program Files\hello.txt" |
"hello" |
pojedyncze rozszerzenie | GetFileBaseNameUsingPath() |
"C:\Program Files\hello.txt" |
"hello" |
Single rozszerzenie | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\hello.txt" |
"hello" |
pojedyncze rozszerzenie | GetFileBaseNameUsingSubstring() |
"C:\Program Files\hello.txt" |
"hello" |
Podwójne rozszerzenie | GetFileBaseNameUsingSplit() |
"C:\Program Files\hello.txt.ext" |
"hello" |
Double rozszerzenie | GetFileBaseNameUsingPath() |
"C:\Program Files\hello.txt.ext" |
"hello.txt" |
Podwójne rozszerzenie | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\hello.txt.ext" |
"hello" |
Podwójne rozszerzenie | GetFileBaseNameUsingSubstring() |
"C:\Program Files\hello.txt.ext" |
"hello" |
Nie rozszerzenie | GetFileBaseNameUsingSplit() |
"C:\Program Files\hello" |
"hello" |
brak rozszerzenia | GetFileBaseNameUsingPath() |
"C:\Program Files\hello" |
"hello" |
brak rozszerzenia | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\hello" |
wyjątek: długość nie może być mniejsza niż zero. (Parametr "długość') |
Nie rozszerzenie | GetFileBaseNameUsingSubstring() |
"C:\Program Files\hello" |
"hello" |
okres wiodący | GetFileBaseNameUsingSplit() |
"C:\Program Files\.hello.txt" |
"" |
okres wiodący | GetFileBaseNameUsingPath() |
"C:\Program Files\.hello.txt" |
".hello" |
prowadzenie okres | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\.hello.txt" |
"" |
okres wiodący | GetFileBaseNameUsingSubstring() |
"C:\Program Files\.hello.txt" |
"" |
okres schyłkowy | GetFileBaseNameUsingSplit() |
"C:\Program Files\hello.txt." |
"hello" |
Trailing okres | GetFileBaseNameUsingPath() |
"C:\Program Files\hello.txt." |
"hello.txt" |
okres schyłkowy | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\hello.txt." |
"hello" |
okres schyłkowy | GetFileBaseNameUsingSubstring() |
"C:\Program Files\hello.txt." |
"hello" |
Katalog ścieżka | GetFileBaseNameUsingSplit() |
"C:\Program Files\" |
"" |
ścieżka katalogu | GetFileBaseNameUsingPath() |
"C:\Program Files\" |
"" |
ścieżka katalogu | GetFileBaseNameUsingSubstringUnsafe() |
"C:\Program Files\" |
wyjątek: długość nie może być mniejsza niż zero. (Parametr "długość') |
Katalog ścieżka | GetFileBaseNameUsingSubstring() |
"C:\Program Files\" |
"" |
bieżąca ścieżka do pliku | GetFileBaseNameUsingSplit() |
"hello.txt" |
"hello" |
bieżąca ścieżka do pliku | GetFileBaseNameUsingPath() |
"hello.txt" |
"hello" |
bieżący plik ścieżka | GetFileBaseNameUsingSubstringUnsafe() |
"hello.txt" |
"hello" |
bieżąca ścieżka do pliku | GetFileBaseNameUsingSubstring() |
"hello.txt" |
"hello" |
ścieżka do pliku nadrzędnego | GetFileBaseNameUsingSplit() |
"..\hello.txt" |
"hello" |
plik nadrzędny ścieżka | GetFileBaseNameUsingPath() |
"..\hello.txt" |
"hello" |
ścieżka do pliku nadrzędnego | GetFileBaseNameUsingSubstringUnsafe() |
"..\hello.txt" |
"hello" |
ścieżka do pliku nadrzędnego | GetFileBaseNameUsingSubstring() |
"..\hello.txt" |
"hello" |
Katalog nadrzędny ścieżka | GetFileBaseNameUsingSplit() |
".." |
"" |
ścieżka katalogu nadrzędnego | GetFileBaseNameUsingPath() |
".." |
"." |
ścieżka katalogu nadrzędnego | GetFileBaseNameUsingSubstringUnsafe() |
".." |
"" |
ścieżka katalogu nadrzędnego | GetFileBaseNameUsingSubstring() |
".." |
"" |
...i zobaczysz, że Path.GetFileNameWithoutExtension()
różne wyniki po przekazaniu ścieżki, w której nazwa pliku ma podwójne rozszerzenie lub początek i/lub koniec .
. Możesz wypróbować go samodzielnie za pomocą poniższego kodu...
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; DR kod w pytaniu nie zachowuje się tak, jak wielu wydaje się oczekiwać w niektórych narożnych przypadkach. Jeśli masz zamiar napisać własny kod manipulacji ścieżką, pamiętaj, aby wziąć pod uwagę...
- ...jak zdefiniować "nazwę pliku bez rozszerzenia" (czy to wszystko przed pierwszym
.
czy wszystko przed ostatnim.
?) - ...pliki z wieloma rozszerzeniami
- ...Pliki bez rozszerzenia
- ...pliki z wiodącym
.
- ...pliki z zakończeniem
.
(prawdopodobnie nie coś, co kiedykolwiek spotkasz w systemie Windows, ale są możliwe ) - ...katalogi z "rozszerzeniem" lub które w inny sposób zawierają
.
- ...ścieżki, które kończą się
\
- ...względny ścieżki
Nie wszystkie ścieżki plików są zgodne ze standardowym wzorem X:\Directory\File.ext
!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-29 03:34:26
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-31 07:08:44
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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-10 13:22:18