首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 解析檔案路徑:取得目錄、檔名與副檔名的多種方法

     編輯:關於C#

前言

從完整檔案路徑解析目錄、檔名、副檔名是檔案處理基礎操作。本文比較 Path 類別、FileInfo、Uri、字串操作與正則表達式等多種方法優劣,提供跨平台相容的最佳實踐。

方法一:System.IO.Path 類別 (標準、推薦)


using System.IO;

string fullPath = @"C:\Projects\MyApp\bin\Debug\net6.0\appsettings.json";

string directory = Path.GetDirectoryName(fullPath); 
// C:\Projects\MyApp\bin\Debug\net6.0

string fileName = Path.GetFileName(fullPath); 
// appsettings.json

string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fullPath); 
// appsettings

string extension = Path.GetExtension(fullPath); 
// .json

string root = Path.GetPathRoot(fullPath); 
// C:\

// 組合路徑
string newPath = Path.Combine(directory, "config", "settings.json");
// C:\Projects\MyApp\bin\Debug\net6.0\config\settings.json

方法二:FileInfo 類別 (物件導向、功能豐富)


var fileInfo = new FileInfo(fullPath);

string directory = fileInfo.DirectoryName;
string fileName = fileInfo.Name;
string nameOnly = Path.GetFileNameWithoutExtension(fileInfo.Name); // 或自行實作
string extension = fileInfo.Extension;
long length = fileInfo.Length;
DateTime created = fileInfo.CreationTime;
bool exists = fileInfo.Exists;
bool isReadOnly = fileInfo.IsReadOnly;

方法三:Uri 類別 (支援網路路徑、URL 解碼)


var uri = new Uri(fullPath); // file:///C:/Projects/... 或 https://...

string localPath = uri.LocalPath; // 解碼後的本機路徑
string fileName = Path.GetFileName(uri.LocalPath);
string directory = Path.GetDirectoryName(uri.LocalPath);

// 處理 URL 編碼路徑
string urlPath = "https://example.com/files/my%20document.pdf";
var urlUri = new Uri(urlPath);
string decodedName = Path.GetFileName(urlUri.LocalPath); // "my document.pdf"

方法四:字串操作 (教學用、不推薦生產環境)


// 原始字串分割 (脆弱、跨平台失效)
string path = @"C:\Folder\file.txt";
int lastSlash = path.LastIndexOf('\\');
int lastDot = path.LastIndexOf('.');

string dir = path.Substring(0, lastSlash); // C:\Folder
string name = path.Substring(lastSlash + 1, lastDot - lastSlash - 1); // file
string ext = path.Substring(lastDot); // .txt

// 問題:Unix 路徑用 '/'、相對路徑、無副檔名、根目錄等邊界情況皆會失效

方法五:正則表達式 (複雜解析需求)


using System.Text.RegularExpressions;

var regex = new Regex(@"^(?.*[\\/])?(?[^\\/]+)(\.(?[^\\/.]+))?$");
var match = regex.Match(fullPath);

if (match.Success)
{
    string dir = match.Groups["dir"].Value.TrimEnd('\\', '/');
    string name = match.Groups["name"].Value;
    string ext = match.Groups["ext"].Success ? "." + match.Groups["ext"].Value : "";
}

跨平台路徑處理最佳實踐


public static class PathHelper
{
    /// 
    /// 取得目錄路徑 (跨平台安全)
    /// 
    public static string GetDirectory(string path)
    {
        if (string.IsNullOrEmpty(path)) return "";
        return Path.GetDirectoryName(path.Replace('/', Path.DirectorySeparatorChar));
    }

    /// 
    /// 取得檔名 (含副檔名)
    /// 
    public static string GetFileName(string path)
    {
        if (string.IsNullOrEmpty(path)) return "";
        return Path.GetFileName(path.Replace('/', Path.DirectorySeparatorChar));
    }

    /// 
    /// 取得不含副檔名的檔名
    /// 
    public static string GetFileNameWithoutExtension(string path)
    {
        return Path.GetFileNameWithoutExtension(GetFileName(path));
    }

    /// 
    /// 取得副檔名 (含點號)
    /// 
    public static string GetExtension(string path)
    {
        return Path.GetExtension(GetFileName(path));
    }

    /// 
    /// 正規化路徑分隔符
    /// 
    public static string Normalize(string path)
    {
        return path?.Replace('/', Path.DirectorySeparatorChar)
                   .Replace('\\', Path.DirectorySeparatorChar);
    }

    /// 
    /// 確保目錄存在
    /// 
    public static void EnsureDirectory(string filePath)
    {
        string dir = GetDirectory(filePath);
        if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
            Directory.CreateDirectory(dir);
    }
}

邊界情況測試

輸入路徑GetDirectoryNameGetFileNameGetExtensionGetFileNameWithoutExtension
C:\Folder\file.txtC:\Folderfile.txt.txtfile
C:\Folder\C:\FolderFolder
C:\FolderC:\FolderFolder
file.txtfile.txt.txtfile
.hidden.hidden.hidden
archive.tar.gzarchive.tar.gz.gzarchive.tar
/home/user/file/home/userfilefile
\\server\share\file.txt\\server\sharefile.txt.txtfile

進階:解析路徑各層級


public static IEnumerable GetPathSegments(string path)
{
    string normalized = Normalize(path);
    string root = Path.GetPathRoot(normalized);
    string relative = normalized.Substring(root.Length);
    
    return relative.Split(new[] { Path.DirectorySeparatorChar }, 
        StringSplitOptions.RemoveEmptyEntries);
}

// 使用
foreach (string segment in GetPathSegments(@"C:\A\B\C\file.txt"))
{
    Console.WriteLine(segment); // A, B, C, file.txt
}

效能比較


using System.Diagnostics;

public void Benchmark()
{
    string path = @"C:\Very\Long\Path\With\Many\Segments\And\A\File\Name\With\Extension.txt";
    int iterations = 1_000_000;
    
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++)
        Path.GetFileName(path);
    Console.WriteLine($"Path.GetFileName: {sw.ElapsedMilliseconds} ms");
    
    sw.Restart();
    for (int i = 0; i < iterations; i++)
        new FileInfo(path).Name;
    Console.WriteLine($"FileInfo.Name: {sw.ElapsedMilliseconds} ms");
    
    sw.Restart();
    for (int i = 0; i < iterations; i++)
    {
        int idx = path.LastIndexOf('\\');
        string _ = path.Substring(idx + 1);
    }
    Console.WriteLine($"String.LastIndexOf: {sw.ElapsedMilliseconds} ms");
}

/*
典型結果 (100萬次):
Path.GetFileName: 45 ms
FileInfo.Name: 120 ms (建立物件開銷)
String.LastIndexOf: 18 ms (最快但不安全)
*/

常見陷阱與解決方案

問題原因解決方案
Unix 路徑失效硬編碼 '\\'使用 Path.DirectorySeparatorChar 或 Path.GetDirectoryName
副檔名判斷錯誤多重副檔名 .tar.gzPath.GetExtension 只取最後一段,需自行處理
相對路徑解析錯誤無根目錄Path.GetFullPath 轉絕對路徑後再解析
URL 路徑含編碼%20 等編碼使用 Uri.LocalPath 自動解碼
網路路徑 UNC雙反斜線開頭Path 類別原生支援 UNC 路徑

總結

解析檔案路徑首選 System.IO.Path 靜態方法:跨平台、效能佳、處理邊界情況完善。FileInfo 適合需同時取得檔案屬性 (大小、時間、權限) 時使用。避免手動字串分割,除非極簡單且確定路徑格式。跨平台專案務必使用 Path.DirectorySeparatorChar 而非硬編碼分隔符。處理 URL/網路路徑時善用 Uri 類別自動解碼與正規化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved