Biorąc pod uwagę ścieżkę systemu plików, czy istnieje krótszy sposób na wyodrębnienie nazwy pliku bez jego rozszerzenia?

260

Programuję w WPF C #. Mam np. Następującą ścieżkę:

C:\Program Files\hello.txt

i chcę helloz niego wyciągnąć .

Ścieżka jest stringpobierana z bazy danych. Obecnie używam następującego kodu, aby podzielić ścieżkę, '\'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();

Działa, ale uważam, że powinno być krótsze i mądrzejsze rozwiązanie tego problemu. Dowolny pomysł?

KMC
źródło
W moim systemie Path.GetFileName("C:\\dev\\some\\path\\to\\file.cs")zwraca ten sam ciąg i z jakiegoś powodu nie konwertuje go do pliku „file.cs”. Jeśli skopiuję / wkleję mój kod do kompilatora online (takiego jak rextester.com ), to zadziała ...?
jbyrd

Odpowiedzi:

29

próbować

System.IO.Path.GetFileNameWithoutExtension(path); 

próbny

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

poniedziałek
źródło
Wygląda na to, że Path.GetFileNameWithoutExtension () nie działa z rozszerzeniem pliku> 3 znaki.
Nolmë Informatique
26

Możesz użyć Path API w następujący sposób:

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

Więcej informacji: Path.GetFileNameWithoutExtension

Peyman
źródło
11

Spróbuj tego:

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

Zwróci „hello” dla fileName.

Tim
źródło
9
string Location = "C:\\Program Files\\hello.txt";

string FileName = Location.Substring(Location.LastIndexOf('\\') +
    1);
raman
źródło
1
+1, ponieważ może to być pomocne w przypadku, gdy działa to jako kopia zapasowa, w której nazwa pliku zawiera nieprawidłowe znaki [<,> itp. W Path.GetInvalidChars ()].
bhuvin
Jest to faktycznie bardzo przydatne podczas pracy ze ścieżką na serwerach ftp UNIX.
s952163
6

Spróbuj tego,

string FilePath=@"C:\mydir\myfile.ext";
string Result=Path.GetFileName(FilePath);//With Extension
string Result=Path.GetFileNameWithoutExtension(FilePath);//Without Extension
Sumanth
źródło
2
Użyłeś dokładnie tych samych metod, które wymieniono w najlepiej głosowanej odpowiedzi.
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
Ganesh Kalidas
źródło
Dziwię się, że FileVersionInfomożna go używać w plikach, które nie zawierają informacji o wersji. Uwaga: GetVersionInfo()można go używać tylko w przypadku ścieżek, które odwołują się do pliku, który już istnieje. Chociaż do uzyskania nazwy pliku można użyć dowolnej klasy, pytanie również wymaga usunięcia rozszerzenia.
BACON
1

Po pierwsze, kod w pytaniu nie generuje opisanego wyniku. Wyodrębnia rozszerzenie pliku ( "txt"), a nie podstawową nazwę pliku ( "hello"). Aby to zrobić, ostatnia linia powinna zadzwonić First(), a nie Last()tak ...

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ą z rzeczy, o których należy pomyśleć w zakresie poprawy tego kodu, jest ilość śmieci, które tworzy:

  • string[]Zawierający jeden stringdla każdego odcinka toru wpath
  • string[]Zawierający co najmniej jedną stringdla każdego .segmentu ostatnią drogępath

Dlatego też, ekstrahowanie nazwy pliku, z drogi próbkowania "C:\Program Files\hello.txt"powinna produkować (tymczasowego) objecty "C:", "Program Files", "hello.txt", "hello", "txt", A string[3]i string[2]. Może to mieć znaczenie, jeśli metoda zostanie wywołana na dużej liczbie ścieżek. Aby to poprawić, możemy przeszukać pathsiebie, aby zlokalizować punkty początkowe i końcowe nazwy bazowej i użyć ich do utworzenia jednego nowego 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;
}

Wykorzystuje to indeks znaku po ostatnim \jako początek nazwy podstawowej, a stamtąd szuka pierwszego, .który będzie używany jako indeks znaku po końcu nazwy podstawowej. Czy to jest krótszy niż oryginalny kod? Nie do końca. Czy to „mądrzejsze” rozwiązanie? Chyba tak. Przynajmniej byłoby tak, gdyby nie fakt, że ...

Jak widać z komentarza, poprzednia metoda jest problematyczna. Chociaż działa, jeśli założysz, że wszystkie ścieżki kończą się nazwą pliku z rozszerzeniem, zgłasza wyjątek, jeśli ścieżka kończy się na \(tj. Ścieżka katalogu) lub w inny sposób nie zawiera rozszerzenia w ostatnim segmencie. Aby to naprawić, musimy dodać dodatkowy czek, aby uwzględnić, kiedy endIndexjest -1(tzn. .Nie został znaleziony) ...

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

Teraz ta wersja nie jest prawie krótsza niż oryginalna, ale jest również bardziej wydajna i (teraz) poprawna.

Jeśli chodzi o metody .NET, które implementują tę funkcjonalność, 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()i Path.GetFileNameWithoutExtension()( GetFileBaseNameUsingPath()poniżej): pierwszy wyodrębnia wszystko przed pierwszym, . a drugi wyodrębnia wszystko przed ostatnim . . Nie ma to znaczenia dla próbki pathw pytaniu, ale spójrz na tabelę porównującą wyniki powyższych czterech metod, gdy są wywoływane z różnymi ścieżkami ...

| 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()   | ".."                             | ""                                                               |
|-----------------------|---------------------------------------|----------------------------------|------------------------------------------------------------------|

... a zobaczysz, że Path.GetFileNameWithoutExtension()daje to inne wyniki, gdy przejdziesz ścieżkę, w której nazwa pliku ma podwójne rozszerzenie lub początkowe i / lub końcowe .. Możesz spróbować samemu, używając następującego 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 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 Kod w pytaniu nie zachowuje się tak, jak wielu wydaje się oczekiwać w niektórych przypadkach narożnych. Jeśli masz zamiar napisać własny kod do manipulacji ścieżką, pamiętaj, aby wziąć pod uwagę ...

  • ... jak zdefiniujesz „rozszerzenie” (czy to wszystko przed pierwszym, .czy wszystko przed ostatnim .?)
  • ... pliki z wieloma rozszerzeniami
  • ... pliki bez rozszerzenia
  • ... pliki z wiodącym .
  • ... pliki ze znakiem końcowym .(prawdopodobnie nie jest to coś, co można napotkać w systemie Windows, ale są one możliwe )
  • ... katalogi z „rozszerzeniem” lub zawierające w inny sposób .
  • ... ścieżki kończące się na \
  • ... ścieżki względne

Nie wszystkie ścieżki plików są zgodne ze zwykłą formułą X:\Directory\File.ext!

BOCZEK
źródło
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>
Ritesh Yadav
źródło
Pytanie dotyczy sposobu wyodrębnienia nazwy pliku bez rozszerzenia ze ścieżki pliku. Zamiast tego pobiera bezpośrednie pliki potomne katalogu, który może, ale nie musi być określony przez plik konfiguracyjny. Nie są tak naprawdę bliskie tej samej rzeczy.
BACON