รับเส้นทางของระบบไฟล์มีวิธีที่สั้นกว่าในการแตกชื่อไฟล์โดยไม่มีนามสกุลหรือไม่?


261

ฉันเขียนโปรแกรมใน 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 ) มันใช้งานได้ ... ?
jbyrd

คำตอบ:




29

ลอง

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 ตัวอักษร
Nolmë Informatique



11

ลองสิ่งนี้:

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

นี่จะส่งคืน "hello" สำหรับชื่อไฟล์


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

string FileName = Location.Substring(Location.LastIndexOf('\\') +
    1);

1
+1 เนื่องจากสิ่งนี้อาจมีประโยชน์ในกรณีที่สิ่งนี้ใช้เป็นข้อมูลสำรองในกรณีที่ชื่อไฟล์มีอักขระที่ไม่ถูกต้อง [<,> ฯลฯ ใน Path.GetInvalidChars ()]
bhuvin

สิ่งนี้มีประโยชน์มากเมื่อทำงานกับพา ธ บนเซิร์ฟเวอร์ UNIX ftp
s952163

6

ลองนี้

string FilePath=@"C:\mydir\myfile.ext";
string Result=Path.GetFileName(FilePath);//With Extension
string Result=Path.GetFileNameWithoutExtension(FilePath);//Without Extension

2
คุณใช้วิธีการเดียวกันตามที่ระบุในคำตอบที่ได้รับคะแนนสูงสุด
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

ฉันประหลาดใจที่FileVersionInfoสามารถใช้กับไฟล์ที่ไม่มีข้อมูลรุ่น โปรดทราบว่าGetVersionInfo()สามารถใช้กับเส้นทางที่อ้างอิงไฟล์ที่มีอยู่แล้วเท่านั้น ในขณะที่คลาสใดสามารถใช้เพื่อรับชื่อไฟล์ได้คำถามก็ขอให้ลบส่วนขยายด้วยเช่นกัน
BACON

1

ประการแรกรหัสในคำถามไม่ได้สร้างผลลัพธ์ที่อธิบายไว้ มันแยกนามสกุลไฟล์( "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;
}

เมื่อทำการเปลี่ยนแปลงแล้วสิ่งหนึ่งที่ควรคำนึงถึงการปรับปรุงรหัสนี้คือปริมาณขยะที่สร้างขึ้น:

  • string[]มีหนึ่งstringสำหรับแต่ละส่วนของเส้นทางในpath
  • A string[]ที่มีอย่างน้อยหนึ่งรายการstringสำหรับแต่ละรายการ.ในส่วนของเส้นทางสุดท้ายpath

ดังนั้นการแยกชื่อไฟล์ฐานจากเส้นทางตัวอย่าง"C:\Program Files\hello.txt"ควรผลิต (ชั่วคราว) objects "C:", "Program Files", "hello.txt", "hello", "txt"เป็นและstring[3] 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( .ไม่พบie ) ...

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

ตอนนี้เวอร์ชั่นนี้แทบจะสั้นกว่าต้นฉบับ แต่ก็มีประสิทธิภาพมากกว่าและถูกต้องแล้ว

เท่าที่วิธีการ. NET ที่ใช้งานฟังก์ชั่นนี้มีคำตอบอื่น ๆ อีกมากมายที่แนะนำให้ใช้Path.GetFileNameWithoutExtension()ซึ่งเป็นวิธีการแก้ปัญหาที่ง่ายและชัดเจน แต่ไม่ได้ให้ผลลัพธ์เหมือนกับรหัสในคำถาม มีความแตกต่างบอบบาง แต่ที่สำคัญระหว่างเป็นGetFileBaseNameUsingSplit()และPath.GetFileNameWithoutExtension()( GetFileBaseNameUsingPath()ด้านล่าง): สารสกัดจากอดีตทุกอย่างก่อนที่จะเป็นครั้งแรก .และสารสกัดจากหลังทุกอย่างก่อนที่สุดท้าย .สิ่งนี้ไม่ได้สร้างความแตกต่างให้กับตัวอย่าง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      | 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()   | ".."                             | ""                                                               |
|-----------------------|---------------------------------------|----------------------------------|------------------------------------------------------------------|

... และคุณจะเห็นว่า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 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 รหัสในคำถามไม่ได้มีพฤติกรรมมากเท่าที่คาดหวังในบางกรณี หากคุณกำลังจะเขียนรหัสการจัดการเส้นทางของคุณเองให้คำนึงถึง ...

  • ... วิธีที่คุณกำหนด "ส่วนขยาย" (คือทุกอย่างก่อนหน้าแรก.หรือทุกอย่างก่อนหน้าสุดท้าย. ?)
  • ... ไฟล์ที่มีนามสกุลหลายรายการ
  • ... ไฟล์ที่ไม่มีนามสกุล
  • ... ไฟล์ที่มีผู้นำ .
  • ... ไฟล์ที่มีส่วนท้าย.(อาจไม่ใช่สิ่งที่คุณจะพบบน Windows แต่เป็นไปได้ )
  • ... ไดเรกทอรีที่มี "ส่วนขยาย" หรือที่ประกอบด้วย .
  • ... เส้นทางที่ลงท้ายด้วย a \
  • ... เส้นทางสัมพัทธ์

เส้นทางของไฟล์ไม่ครบทุกสูตรตามปกติX:\Directory\File.ext!


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>

คำถามกำลังถามวิธีแตกชื่อไฟล์โดยไม่มีนามสกุลจากพา ธ ไฟล์ สิ่งนี้แทนกำลังเรียกคืนไฟล์ย่อยทันทีของไดเร็กทอรีที่อาจหรือไม่อาจระบุโดยไฟล์คอนฟิกูเรชัน สิ่งเหล่านั้นไม่ใกล้เคียงกับสิ่งเดียวกันจริงๆ
BACON
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.