Étant donné un chemin d'accès au système de fichiers, existe-t-il un moyen plus court d'extraire le nom de fichier sans son extension?

261

Je programme en WPF C #. J'ai par exemple le chemin suivant:

C:\Program Files\hello.txt

et je veux en extraire hello.

Le chemin d'accès est stringextrait d'une base de données. Actuellement, j'utilise le code suivant pour diviser le chemin par '\', puis à nouveau diviser par '.':

string path = "C:\\Program Files\\hello.txt";
string[] pathArr = path.Split('\\');
string[] fileArr = pathArr.Last().Split('.');
string fileName = fileArr.Last().ToString();

Cela fonctionne, mais je pense qu'il devrait y avoir une solution plus courte et plus intelligente à cela. Une idée?

KMC
la source
Dans mon système, Path.GetFileName("C:\\dev\\some\\path\\to\\file.cs")renvoie la même chaîne et ne la convertit pas en "file.cs" pour une raison quelconque. Si je copie / colle mon code dans un compilateur en ligne (comme rextester.com ), cela fonctionne ...?
jbyrd

Réponses:

29

essayer

System.IO.Path.GetFileNameWithoutExtension(path); 

démo

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

Lundi
la source
Il semble que Path.GetFileNameWithoutExtension () ne fonctionne pas avec une extension de fichier> 3 caractères.
Nolmë Informatique
26

Vous pouvez utiliser l' API Path comme suit:

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

Plus d'informations: Path.GetFileNameWithoutExtension

Peyman
la source
11

Essaye ça:

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

Cela renverra "bonjour" pour fileName.

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

string FileName = Location.Substring(Location.LastIndexOf('\\') +
    1);
raman
la source
1
+1 car cela peut être utile dans le cas où cela fonctionne comme une sauvegarde dans laquelle le nom de fichier contient des caractères non valides [<,> etc. dans Path.GetInvalidChars ()].
bhuvin
Ceci est en fait très utile lorsque vous travaillez avec un chemin sur des serveurs ftp UNIX.
s952163
6

Essaye ça,

string FilePath=@"C:\mydir\myfile.ext";
string Result=Path.GetFileName(FilePath);//With Extension
string Result=Path.GetFileNameWithoutExtension(FilePath);//Without Extension
Sumanth
la source
2
Vous avez utilisé exactement les mêmes méthodes que celles mentionnées dans la réponse la plus votée.
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
la source
Je suis surpris que cela FileVersionInfopuisse être utilisé sur des fichiers qui n'ont pas d'informations sur la version. Notez que GetVersionInfo()cela ne peut être utilisé que sur des chemins faisant référence à un fichier qui existe déjà. Bien que l'une ou l'autre classe puisse être utilisée pour obtenir le nom du fichier, la question a également demandé de supprimer l'extension également.
BACON
1

Premièrement, le code dans la question ne produit pas la sortie décrite. Il extrait l' extension de fichier ( "txt") et non le nom de base du fichier ( "hello"). Pour ce faire, la dernière ligne doit appeler First(), pas Last(), comme ça ...

static string GetFileBaseNameUsingSplit(string path)
{
    string[] pathArr = path.Split('\\');
    string[] fileArr = pathArr.Last().Split('.');
    string fileBaseName = fileArr.First().ToString();

    return fileBaseName;
}

Après avoir apporté ce changement, une chose à laquelle penser en ce qui concerne l'amélioration de ce code est la quantité de déchets qu'il crée:

  • Un string[]contenant un stringpour chaque segment de chemin danspath
  • Un string[]contenant au moins un stringpour chacun .dans le dernier segment de cheminpath

Par conséquent, extraire le nom du fichier de base à partir du chemin d'échantillon "C:\Program Files\hello.txt"doit produire le (temporaire) objects "C:", "Program Files", "hello.txt", "hello", "txt", un string[3], et un string[2]. Cela peut être significatif si la méthode est appelée sur un grand nombre de chemins. Pour améliorer cela, nous pouvons rechercher pathnous-mêmes pour localiser les points de début et de fin du nom de base et les utiliser pour en créer un nouveau 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;
}

C'est utiliser l'index du caractère après le dernier \comme début du nom de base, et à partir de là chercher le premier .à utiliser comme index du caractère après la fin du nom de base. Est-ce plus court que le code d'origine? Pas assez. Est-ce une solution "plus intelligente"? Je le pense. Du moins, ce serait sans le fait que ...

Comme vous pouvez le voir dans le commentaire, la méthode précédente est problématique. Bien que cela fonctionne si vous supposez que tous les chemins se terminent par un nom de fichier avec une extension, il lèvera une exception si le chemin se termine par \(c'est-à-dire un chemin de répertoire) ou ne contient aucune extension dans le dernier segment. Pour résoudre ce problème, nous avons besoin d'ajouter un contrôle supplémentaire pour compte quand endIndexest -1(c. -à- .ne se trouve pas) ...

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

Maintenant, cette version est loin d'être plus courte que l'original, mais elle est plus efficace et (maintenant) correcte aussi.

En ce qui concerne les méthodes .NET qui implémentent cette fonctionnalité, de nombreuses autres réponses suggèrent d'utiliser Path.GetFileNameWithoutExtension(), ce qui est une solution évidente et facile mais ne produit pas les mêmes résultats que le code de la question. Il y a une différence subtile mais importante entre GetFileBaseNameUsingSplit()et Path.GetFileNameWithoutExtension()( GetFileBaseNameUsingPath()ci-dessous): le premier extrait tout avant le premier . et le dernier extrait tout avant le dernier . . Cela ne fait aucune différence pour l'échantillon pathde la question, mais jetez un œil à ce tableau comparant les résultats des quatre méthodes ci-dessus lorsqu'ils sont appelés avec différents chemins ...

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

... et vous verrez que cela Path.GetFileNameWithoutExtension()donne des résultats différents lorsque vous passez un chemin où le nom de fichier a une double extension ou un début et / ou une fin .. Vous pouvez l'essayer par vous-même avec le code suivant ...

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 Le code dans la question ne se comporte pas comme beaucoup semblent s'y attendre dans certains cas de coin. Si vous allez écrire votre propre code de manipulation de chemin, assurez-vous de prendre en considération ...

  • ... comment définir une "extension" (est-ce tout avant le premier .ou tout avant le dernier .?)
  • ... des fichiers avec plusieurs extensions
  • ... fichiers sans extension
  • ... des fichiers avec un leader .
  • ... des fichiers avec un suivi .(probablement pas quelque chose que vous rencontrerez jamais sur Windows, mais ils sont possibles )
  • ... répertoires avec une "extension" ou qui contiennent autrement un .
  • ... des chemins qui se terminent par un \
  • ... chemins relatifs

Tous les chemins de fichiers ne suivent pas la formule habituelle de X:\Directory\File.ext!

BACON
la source
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
la source
La question est de savoir comment extraire le nom de fichier sans extension d'un chemin de fichier. Il s'agit plutôt de récupérer les fichiers enfants immédiats d'un répertoire qui peut ou non être spécifié par un fichier de configuration. Ce ne sont pas vraiment proches de la même chose.
BACON