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

路徑、檔案、目錄、I/O 常見操作總彙整 (二) — FileInfo、DirectoryInfo、DriveInfo 完整操作指南

     編輯:關於.NET

前言

承接第一篇 (路徑操作、常用對話框),本篇深入 檔案、目錄、磁碟機實體操作:FileInfo、DirectoryInfo、DriveInfo 三大核心類別。掌握屬性存取、建立/複製/移動/刪除、搜尋、版本資訊、大小計算、屬性位元組合操作等實戰技巧。

核心類別繼承關係

FileSystemInfo (abstract)
    ├─ FileInfo          -- 檔案實體
    └─ DirectoryInfo     -- 目錄實體
DriveInfo                -- 獨立,不繼承 FileSystemInfo
File / Directory         -- 靜態方法類別,單次操作效率較高
關鍵差異:FileInfo/DirectoryInfo 實例化時不檢查存在性,屬性值為首次查詢快取,後續需呼叫 Refresh() 更新;DriveInfo 屬性每次即時讀取;File/Directory 靜態方法每次皆執行安全性檢查。

一、FileInfo — 檔案實體操作

常用屬性

屬性型別說明
Existsbool檔案是否存在 (首次查詢快取)
Name / FullNamestring檔名 / 完整路徑
Extensionstring副檔名 (含點號)
Directory / DirectoryNameDirectoryInfo / string所在目錄物件 / 目錄路徑
Lengthlong檔案大小 (位元組)
IsReadOnlybool唯讀屬性
AttributesFileAttributes檔案屬性位元旗標 (可組合)
CreationTime / LastAccessTime / LastWriteTimeDateTime建立/存取/修改時間

屬性位元操作 — 正確判斷與設定


var fi = new FileInfo(@"C:\Test\data.txt");

// 判斷唯讀 (錯誤寫法:fi.Attributes == FileAttributes.ReadOnly 會因其他屬性失敗)
bool isReadOnly = (fi.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;

// 設定唯讀
fi.Attributes |= FileAttributes.ReadOnly;      // 加入旗標
fi.Attributes &= ~FileAttributes.ReadOnly;     // 移除旗標
fi.Attributes ^= FileAttributes.Hidden;        // 切換隱藏

// 批次設定多個屬性
fi.Attributes = FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.Archive;
fi.Refresh(); // 重新讀取檔案系統更新屬性

檔案版本資訊 — FileVersionInfo


var fvi = FileVersionInfo.GetVersionInfo(@"C:\Windows\Notepad.exe");
Console.WriteLine($"檔案版本: {fvi.FileVersion}");
Console.WriteLine($"產品版本: {fvi.ProductVersion}");
Console.WriteLine($"公司名稱: {fvi.CompanyName}");
Console.WriteLine($"版權宣告: {fvi.LegalCopyright}");
Console.WriteLine($"內部名稱: {fvi.InternalName}");
Console.WriteLine($"原始檔名: {fvi.OriginalFilename}");

檔案內容判等 — 雜湊比對 (SHA256)


using System.Security.Cryptography;

public static bool FilesContentEqual(string path1, string path2)
{
    using (var sha = SHA256.Create())
    using (var fs1 = File.OpenRead(path1))
    using (var fs2 = File.OpenRead(path2))
    {
        byte[] hash1 = sha.ComputeHash(fs1);
        byte[] hash2 = sha.ComputeHash(fs2);
        return StructuralComparisons.StructuralEqualityComparer.Equals(hash1, hash2);
    }
}

檔案操作方法

方法說明備註
CopyTo(dest, overwrite)複製檔案overwrite=true 覆蓋既有
MoveTo(dest)移動/重命名跨磁碟機自動複製+刪除
Delete()刪除檔案不存在不拋例外
Replace(dest, backup, ignoreMetadata)以目前檔案取代目標,備份舊檔原子性替換,適合熱更新
Create() / CreateText() / Open(mode)建立/開啟 FileStream回傳 Stream 供讀寫

二、DirectoryInfo — 目錄實體操作

常用屬性

屬性型別說明
Existsbool目錄是否存在
Name / FullNamestring目錄名 / 完整路徑
Parent / RootDirectoryInfo父目錄 / 根目錄
Attributes / CreationTime / LastAccessTime / LastWriteTime同 FileInfo

列舉檔案與子目錄


var di = new DirectoryInfo(@"C:\Source");

// 取得檔案 (支援萬用字元、遞迴)
FileInfo[] files = di.GetFiles("*.log", SearchOption.AllDirectories);
FileInfo[] filesTop = di.GetFiles("*.txt"); // 僅最上層

// 取得子目錄
DirectoryInfo[] dirs = di.GetDirectories("*", SearchOption.TopDirectoryOnly);

// 取得檔案+目錄混合
FileSystemInfo[] all = di.GetFileSystemInfos("*.cs", SearchOption.AllDirectories);

遞迴計算目錄大小


public static long GetDirectorySize(DirectoryInfo dir, bool includeSubDir = true)
{
    long size = 0;
    try
    {
        foreach (var f in dir.GetFiles()) size += f.Length;
        if (includeSubDir)
            foreach (var d in dir.GetDirectories()) size += GetDirectorySize(d, true);
    }
    catch (UnauthorizedAccessException) { /* 忽略無權限目錄 */ }
    return size;
}

目錄操作方法

方法說明
Create()建立目錄 (含中間層級)
CreateSubdirectory(path)建立子目錄
MoveTo(dest)移動/重命名目錄 (含內容)
Delete(recursive)刪除目錄,recursive=true 刪除內容

目錄複製 (FileInfo 無 CopyTo 目錄方法,需自行遞迴)


public static void CopyDirectory(DirectoryInfo source, DirectoryInfo target)
{
    if (target.FullName.Equals(source.FullName, StringComparison.OrdinalIgnoreCase)) return;
    if (!target.Exists) target.Create();
    
    foreach (var file in source.GetFiles())
        file.CopyTo(Path.Combine(target.FullName, file.Name), true);
    
    foreach (var dir in source.GetDirectories())
        CopyDirectory(dir, target.CreateSubdirectory(dir.Name));
}

三、DriveInfo — 磁碟機資訊


// 取得所有邏輯磁碟機
DriveInfo[] drives = DriveInfo.GetDrives();

foreach (var d in drives)
{
    Console.WriteLine($"磁碟機: {d.Name}");                    // C:\
    Console.WriteLine($"  類型: {d.DriveType}");                // Fixed, CDRom, Removable, Network, Ram, Unknown
    Console.WriteLine($"  格式: {d.DriveFormat}");              // NTFS, FAT32, exFAT, CDFS
    Console.WriteLine($"  就緒: {d.IsReady}");                  // false 表示無媒體 (如空光碟機)
    if (d.IsReady)
    {
        Console.WriteLine($"  可用空間: {d.AvailableFreeSpace:N0} bytes");  // 考慮磁碟配額
        Console.WriteLine($"  總可用空間: {d.TotalFreeSpace:N0} bytes");
        Console.WriteLine($"  總容量: {d.TotalSize:N0} bytes");
        Console.WriteLine($"  根目錄: {d.RootDirectory.FullName}");
    }
}

四、File / Directory 靜態方法 vs 實例方法選擇

情境建議理由
單次操作、不重用路徑File.Copy / Directory.GetFiles 等靜態方法程式碼簡潔、內部快取路徑字串
同一路徑多次操作 (屬性、移動、刪除)FileInfo / DirectoryInfo 實例避免重複安全性檢查、可呼叫 Refresh()
需要檔案/目錄屬性快取實例方法首次查詢快取,後續存取極快
高頻率、大量檔案批次處理靜態方法 + 並行避免建立大量物件開銷

五、常見例外處理模式


try
{
    fi.CopyTo(dest, true);
}
catch (FileNotFoundException) { /* 來源不存在 */ }
catch (DirectoryNotFoundException) { /* 目錄不存在 */ }
catch (UnauthorizedAccessException) { /* 權限不足 */ }
catch (IOException ex) when (ex.HResult == -2147024864) { /* 檔案被鎖定/共用違規 */ }
catch (PathTooLongException) { /* 路徑超過 260 字元 */ }
catch (NotSupportedException) { /* 路徑格式無效 */ }

六、路徑過長 ( > 260 字元) 解決方案

  1. .NET 4.6.2+ / .NET Core:專案 .csproj 加入 `true`,並使用 `\\?\` 前綴:var fi = new FileInfo(@"\\?\C:\Very\Long\Path\file.txt");
  2. .NET Framework 舊版:P/Invoke CopyFileW、DeleteFileW 等 Unicode API。
  3. 縮短路徑:使用 `subst` 映射虛擬磁碟機、啟用 NTFS 長路徑支援 (群組原則)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved