天天看點

C#路徑/檔案/目錄/I/O常見操作彙總

<b>主要内容:</b>

一、路徑的相關操作, 如判斷路徑是否合法,路徑類型,路徑的特定部分,合并路徑,系統檔案夾路徑等内容;

二、相關通用檔案對話框,這些對話框可以幫助我們操作檔案系統中的檔案和目錄;

三、檔案、目錄、驅動器的操作,如擷取它們的基本資訊,擷取和設定檔案和目錄的屬性,檔案的版本資訊,

搜尋檔案和目錄,檔案判等,複制、移動、删除、重命名檔案和目錄;

四、讀寫檔案,包括臨時檔案,随機檔案名等;

五、對檔案系統的監視; 

這一篇就先寫一下前兩部分。

一、路徑相關操作

問題1:如何判定一個給定的路徑是否有效/合法;

解決方案:通過Path.GetInvalidPathChars或Path.GetInvalidFileNameChars方法獲得非法的路徑/檔案名字元,可以

根據它來判斷路徑中是否包含非法字元;

問題2:如何确定一個路徑字元串是表示目錄還是檔案;

解決方案:

1、使用Directory.Exists或File.Exist方法,如果前者為真,則路徑表示目錄;如果後者為真,則路徑表示檔案;

2、上面的方法有個缺點就是不能處理那些不存在的檔案或目錄。這時可以考慮使用Path.GetFileName方法獲得

其包含的檔案名,如果一個路徑不為空,而檔案名為空那麼它表示目錄,否則表示檔案;

問題3:如何獲得路徑的某個特定部分(如檔案名、擴充名等);

下面是幾個相關方法:

Path.GetDirectoryName :傳回指定路徑字元串的目錄資訊;

Path.GetExtension : 傳回指定的路徑字元串的擴充名;

Path.GetFileName : 傳回指定路徑字元串的檔案名和擴充名;

Path.GetFileNameWithoutExtension :傳回不具有擴充名的路徑字元串的檔案名;

Path.GetPathRoot :擷取指定路徑的根目錄資訊;

(更多内容還請參考MSDN)

問題4:如何準确地合并兩個路徑而不用去擔心那個煩人的”\”字元;

使用Path.Combine方法,它會幫你處理煩人的”\”;

問題5:如何獲得系統目錄的的路徑(如桌面,我的檔案,臨時檔案夾等);

主要是使用System. Environment類的相關屬性和方法:

Environment. SystemDirectory屬性:擷取系統目錄的完全限定路徑;

Environment. GetFolderPath方法:該方法接受的參數類型為Environment.SpecialFolder枚舉,

通過這個方法可以獲得大量系統檔案夾的路徑,如我的電腦,我的電腦,桌面,系統目錄等;

(更多内容還請參考MSDN);

Path.GetTempPath方法:傳回目前系統的臨時檔案夾的路徑;

問題6:如何判斷一個路徑是絕對路徑還是相對路徑;

使用Path.IsPathRooted方法;

問題7:如何讀取或設定目前目錄;

使用Directory類的GetCurrentDirectory和SetCurrentDirectory方法;

問題8:如何使用相對路徑;

設定目前目錄後(見問題7),就可以使用相對路徑了。對于一個相對路徑,我們可以

使用Path.GetFullPath方法獲得它的完全限定路徑(絕對路徑)。

注意:如果打算使用相對路徑,建議你将工作目錄設定為各個互動檔案的共同起點,否則可能會引入

一些不易發現的安全隐患,被惡意使用者利用來通路系統檔案。

更多内容:

通常我們可以使用System.IO.Path類來處理路徑。該類提供了一套方法和屬性用于對包含檔案或目錄路徑資訊的字元串執行操作,這些操作是以跨平台的方式執行的,而這些方法和屬性都是靜态的。

注意路徑僅僅是提供檔案或目錄位置的字元串。路徑不必指向磁盤上的位置,例如,路徑可以映射到記憶體中或裝置上的位置。路徑的準确格式是由目前平台确定的。例如,在某些系統上,路徑可以驅動器号或卷号開始,而此元素在其他系統中是不存在的。在某些系統上,檔案路徑可以包含擴充名,擴充名訓示在檔案中存儲的資訊的類型。檔案擴充名的格式是與平台相關的;例如,某些系統将擴充名的長度限制為 3 個字元,而其他系統則沒有這樣的限制。目前平台還确定用于分隔路徑中各元素的字元集,以及确定在指定路徑時不能使用的字元集。因為這些差異,是以 Path 類的字段以及 Path 類的某些成員的準确行為是與平台相關的。

路徑可以包含絕對或相對位置資訊。絕對路徑完整指定一個位置:檔案或目錄可被唯一辨別,而與目前位置無關。相對路徑指定部分位置:當定位用相對路徑指定的檔案時,目前位置用作起始點。

Path類的大多數成員不與檔案系統互動,并且不驗證路徑字元串指定的檔案是否存在。修改路徑字元串的Path 類成員(例如 ChangeExtension)對檔案系統中檔案的名稱沒有影響。但Path成員确實驗證指定路徑字元串的内容;并且如果字元串包含在路徑字元串中無效的字元(如 InvalidPathChars 中的定義),則引發 ArgumentException異常。例如,在基于 Windows 的桌面平台上,無效路徑字元可能包括引号 (")、小于号 (&lt;)、大于号 (&gt;)、管道符号 (|)、倒退 (\b)、空 (\0) 以及從 16 到 18 和從 20 到 25的 Unicode 字元。

Path 類的成員使您可以快速友善地執行常見操作,例如确定檔案擴充名是否是路徑的一部分,以及将兩個字元串組合成一個路徑名。

多數情況下,如果這些方法接收了無效的路徑會抛出異常,但如果路徑名是因為包含了通配符(*或?)進而無效,則不會抛出異常(可以使用GetInvalidPathChars方法來非法的路徑字元)。我們可以根據該原則判斷一個路徑是否合法。

二、相關的通用檔案對話框 

1、檔案夾浏覽對話框(FolderBrowserDialog類)

使用者可以通過該對話框浏覽、建立并選擇檔案夾 

主要屬性:

Description:樹視圖控件上顯示的說明文本,如上圖中的”選擇要進行計算的目錄”;

RootFolder:擷取或設定從其開始浏覽的根檔案夾,如上圖中設定的我的電腦(預設為桌面);

SelectedPath:擷取或設定使用者標明的路徑,如果設定了該屬性,打開對話框時會定位到指定路徑,預設為根檔案夾,關閉對話框時根據該屬性擷取使用者使用者標明的路徑;

ShowNewFolderButton:擷取或設定是否顯示建立對話框按鈕;

主要方法:

ShowDialog:打開該對話框,傳回值為DialogResult類型值,如果為DialogResult.OK,則可以由SelectedPath屬性擷取使用者標明的路徑;

dlgOpenFolder.Description = "選擇要進行計算的目錄";

    dlgOpenFolder.RootFolder = Environment.SpecialFolder.MyComputer;

    dlgOpenFolder.ShowNewFolderButton = true;

    DialogResult result = dlgOpenFolder.ShowDialog(this);

    if (result == DialogResult.OK)

    {

        txtDirPath.Text = dlgOpenFolder.SelectedPath;

    }

2、打開檔案對話框(OpenFileDialog類)

使用者可以通過該對話框選擇一個檔案

CheckFileExists:該值訓示如果使用者指定不存在的檔案名,對話框是否顯示警告;

FileName(s):擷取或設定一個包含在檔案對話框中標明的檔案名的字元串;

Filter:擷取或設定對話框的檔案類型清單;

FilterIndex:對話框的檔案類型清單的索引(基于1的);

InitialDirectory:擷取或設定檔案對話框顯示的初始目錄;

Multiselect:該值訓示對話框是否允許選擇多個檔案;

ShowReadOnly:該值訓示對話框是否包含隻讀複選框;

Title:擷取或設定檔案對話框标題;

OpenFile:打開使用者標明的具有隻讀權限的檔案;

ShowDialog:打開該模式對話框; 

dlgOpenFile.Title = "打開源檔案";

    dlgOpenFile.InitialDirectory = @"C:\Inetpub\";

    dlgOpenFile.Filter = "文本檔案 (*.txt)|*.txt|所有檔案 (*.*)|*.*";

    dlgOpenFile.FilterIndex = 2;

    dlgOpenFile.ShowReadOnly = true;

    DialogResult dr = dlgOpenFile.ShowDialog();

    if (dr == DialogResult.OK)

        string fileName = dlgOpenFile.FileName;

3、儲存檔案對話框(SaveFileDialog類)

使用者可以通過該對話框儲存一個檔案

大部分與打開檔案對話框類似,此處略過,下面幾個值得注意:

CreatePrompt:該值訓示如果使用者指定不存在的檔案,是否提示使用者允許建立該檔案;

OverwritePrompt:該值訓示如果使用者指定的檔案名已存在,對話框是否顯示警告;

OpenFile:打開使用者標明的具有讀/寫權限的檔案;

ShowDialog:打開該模式對話框;

示例代碼:

dlgSaveFile.Title = "打開目标檔案";

    dlgSaveFile.InitialDirectory = @"C:\Inetpub\";

    dlgSaveFile.Filter = "文本檔案 (*.txt)|*.txt|所有檔案 (*.*)|*.*";

    dlgSaveFile.FilterIndex = 2;

    DialogResult dr = dlgSaveFile.ShowDialog();

        string fileName = dlgSaveFile.FileName;

至此,我們操作的都隻是路徑,要知道,這些路徑僅僅是字元串,還沒有涉及到檔案系統中的真實檔案。 

三、檔案和目錄相關操作

檔案和目錄操作涉及的類主要是:FileInfo,DirectoryInfo,DriveInfo,可以認為它們的一個執行個體對應着一個檔案、目錄、驅動器。它們的用法類似,一般是将檔案、目錄或驅動器的路徑作為參數傳遞給相應的構造函數建立一個執行個體,然後通路它們的屬性和方法。

注意下面幾點:

FileInfo 類和 DirectoryInfo 類都繼承自抽象類 FileSystemInfo , FileSystemInfo 類定義了一些通用的屬性,如 CreationTime 、 Exists 等。但 DriveInfo 類沒有繼承 FileSystemInfo 類,是以它也就沒有上面提到的那些通用屬性了。

FileInfo 類和 DirectoryInfo 類的對象公開的屬性值都是第一次查詢時擷取的值,如果在以此查詢之後檔案或目錄發生了改動,就必須調用它們的 Refresh 方法來更新這些屬性。但 DriveInfo 則無需這麼做,它的屬性每次都會讀取檔案系統最新的資訊。

在建立檔案、目錄或驅動器的執行個體時,如果使用了一個不存在的路徑,并不會報錯,這是你得到一個對象,該對象表示一個并不存在的實體,這意味着它的 Exists 屬性(對于 DriveInfo 來說是 IsReady 屬性)值為 false 。你仍然可以操作該實體,但如果嘗試其它的大多數屬性,就會引發相應的 FileNotFoundException 、 DirectoryNotFoundException 或 DriveNotFoundException 異常。

另外,還可以使用 File / Directory 類,這兩個類的成員都是靜态方法,是以如果隻想執行一個操作,那麼使用 File/Directory 中的靜态方法的效率比使用相應的 FileInfo / DirectoryInfo中的 執行個體方法可能更高。所有的 File / Directory 方法都要求目前所操作的檔案 / 目錄的路徑。 注意: File / Directory 類的靜态方法對所有方法都執行安全檢查。如果打算多次重用某個對象,可考慮改用 FileInfo / DirectoryInfo 的相應執行個體方法,因為并不總是需要安全檢查。 

下面是一些常見的問題:

問題1:如何擷取指定檔案的基本資訊;

解決方案:可以使用FileInfo類的相關屬性:

FileInfo.Exists:擷取指定檔案是否存在;

FileInfo.Name,FileInfo.Extensioin:擷取檔案的名稱和擴充名;

FileInfo.FullName:擷取檔案的全限定名稱(完整路徑);

FileInfo.Directory:擷取檔案所在目錄,傳回類型為DirectoryInfo;

FileInfo.DirectoryName:擷取檔案所在目錄的路徑(完整路徑);

FileInfo.Length:擷取檔案的大小(位元組數);

FileInfo.IsReadOnly:擷取檔案是否隻讀;

FileInfo.Attributes:擷取或設定指定檔案的屬性,傳回類型為FileAttributes枚舉,可以是多個值的組合(見問題2);

FileInfo.CreationTime、FileInfo.LastAccessTime、FileInfo.LastWriteTime:分别用于擷取檔案的建立時間、通路時間、修改時間;

問題2:如何擷取和設定檔案的屬性,比如隻讀、存檔、隐藏等;

使用FileInfo.Attributes屬性可以擷取和設定檔案的屬性,該屬性類型為FileAttributes枚舉,該枚舉的每個值表示一種屬性,FileAttributes枚舉具有屬性(Attribute)FlagsAttribute,是以該枚舉的值可以進行組合,也就是一個檔案可以同時擁有多個屬性。下面看看具體的做法:

擷取屬性,比如判斷一個檔案是否是隻讀的:

// 當檔案具有其它屬性時,這種做法會失敗

    if (file.Attributes == FileAttributes.ReadOnly)

        chkReadonly.Checked = true;

    // 這種寫法就不會有問題了,它隻檢查隻讀屬性

    if ((file.Attributes &amp; FileAttributes.ReadOnly) == FileAttributes.ReadOnly)

設定屬性,比如添加和移除一個檔案的隻讀屬性:

if (chkReadonly.Checked)

        // 添加隻讀屬性

        file.Attributes |= FileAttributes.ReadOnly;

    else

        // 移除隻讀屬性

        file.Attributes &amp;= ~FileAttributes.ReadOnly;

問題3:如何擷取檔案的版本資訊(比如版本号,版權聲明,公司名稱等);

使用FileVersionInfo類,該類有大量的版本資訊相關的屬性。通過它的靜态方法GetVersionInfo獲得該類的一個執行個體,然後就可以通路指定檔案的版本資訊了,非常友善。如FileVersion表示檔案版本号,LegalCopyright表示指定檔案的版權聲明,CompanyName表示指定檔案的公司名稱。(更多内容還請參考MSDN)

問題4:如何判斷兩個檔案的内容是否相同(精确比對);

使用System.security.Cryptography.HashAlgorithm類為每個檔案生成一個哈希碼,然後比較兩個哈希碼是否一緻。

在比較檔案内容的時候可以采用好幾種方法。例如,檢查檔案的某一特定部分是否一緻;如果願意,你甚至可以逐位元組讀取檔案,逐位元組進行比較。這兩種方法都是可以的,但在某些情況下,還是使用哈希碼算法更為友善。

該算法為一個檔案生成一個小的(通常約為20位元組)二進制”指紋”(binary fingerprint)。從統計學角度看,不同的檔案不可能生成相同的哈希碼。事實上,即使是一個很小的改動(比如,修改了源檔案中的一個bit),也會有50%的幾率來改變哈希碼中的每一個bit。是以,哈希碼常常用于資料安全方面。

要生成一個哈希碼,你必須首先建立一個HashAlgorithm對象,而這通常是調用HashAlgorithm.Create方法來完成的;然後調用HashAlgorithm.ComputeHash方法,它會傳回一個存儲哈希碼的位元組數組。代碼如下:

/// &lt;summary&gt;

    /// 判斷兩個檔案内容是否一緻

    /// &lt;/summary&gt;

    public static bool IsFilesEqual(string fileName1, string fileName2)

        using (HashAlgorithm hashAlg = HashAlgorithm.Create())

        {

            using (FileStream fs1 = new FileStream(fileName1, FileMode.Open), fs2 = new FileStream(fileName2, FileMode.Open))

            {

                byte[] hashBytes1 = hashAlg.ComputeHash(fs1);

                byte[] hashBytes2 = hashAlg.ComputeHash(fs2);

                // 比較哈希碼

                return (BitConverter.ToString(hashBytes1) == BitConverter.ToString(hashBytes2));

            }

        }

問題5:如何擷取指定目錄的基本資訊;

解決方案:可以使用DirectoryInfo類的相關屬性和方法:

DirectoryInfo.Exists:擷取指定目錄是否存在;

DirectoryInfo.Name:擷取目錄的名稱;

DirectoryInfo.FullName:擷取目錄的全限定名稱(完整路徑);

DirectoryInfo.Attributes:擷取或設定指定目錄的屬性,傳回類型為FileAttributes枚舉,可以是多個值的組合; 

DirectoryInfo.CreationTime、FileInfo.LastAccessTime、FileInfo.LastWriteTime:分别用于擷取目錄的建立時間、通路時間、修改時間;

DirectoryInfo.Parent:擷取目錄的上級目錄,傳回類型為DirectoryInfo;

DirectoryInfo.Root:擷取目錄的根目錄,傳回類型為DirectoryInfo;

問題6:如何擷取指定目錄包含的檔案和子目錄;

DirectoryInfo.GetFiles():擷取目錄中(不包含子目錄)的檔案,傳回類型為FileInfo[],支援通配符查找;

DirectoryInfo.GetDirectories():擷取目錄(不包含子目錄)的子目錄,

傳回類型為DirectoryInfo[],支援通配符查找;

DirectoryInfo. GetFileSystemInfos():擷取指定目錄下(不包含子目錄)的檔案和子目錄,

傳回類型為FileSystemInfo[],支援通配符查找;

問題7:如何獲得指定目錄的大小;

檢查目錄内的所有檔案,利用FileInfo.Length屬性擷取每個檔案的大小,然後進行合計,然後使用遞歸算法處理所有的子目錄的檔案,參考下面代碼:

    /// 計算一個目錄的大小

    /// &lt;param name="di"&gt;指定目錄&lt;/param&gt;

    /// &lt;param name="includeSubDir"&gt;是否包含子目錄&lt;/param&gt;

    /// &lt;returns&gt;&lt;/returns&gt;

    private long CalculateDirSize(DirectoryInfo di, bool includeSubDir)

        long totalSize = 0;

        // 檢查所有(直接)包含的檔案

        FileInfo[] files = di.GetFiles();

        foreach (FileInfo file in files)

            totalSize += file.Length;

        // 檢查所有子目錄,如果includeSubDir參數為true

        if (includeSubDir)

            DirectoryInfo[] dirs = di.GetDirectories();

            foreach (DirectoryInfo dir in dirs)

                totalSize += CalculateDirSize(dir, includeSubDir);

        return totalSize;

問題8:如何使用通配符搜尋指定目錄内的所有檔案;

使用DirectoryInfo.GetFiles方法的重載版本,它可以接受一個過濾表達式,傳回FileInfo數組,另外它的參數還可以指定是否對子目錄進行查找。如:

dir.GetFiles("*.txt", SearchOption.AllDirectories);

問題9:如何複制、移動、重命名、删除檔案和目錄;

解決方案:使用FileInfo和DirectoryInfo類。

下面是FileInfo類的相關方法:

FileInfo.CopyTo:将現有檔案複制到新檔案,其重載版本還允許覆寫已存在檔案;

FileInfo.MoveTo:将指定檔案移到新位置,并提供指定新檔案名的選項,是以可以用來重命名檔案(而不改變位置); FileInfo.Delete:永久删除檔案,如果檔案不存在,則不執行任何操作;

FileInfo.Replace:使用目前FileInfo對象對應檔案的内容替換目标檔案,而且指定另一個檔案名作為被替換檔案的備份,微軟考慮實在周到。

下面是DirectoryInfo類的相關方法:

DirectoryInfo.Create:建立指定目錄,如果指定路徑中有多級目錄不存在,該方法會一一建立;

DirectoryInfo.CreateSubdirectory:建立目前對象對應的目錄的子目錄;

DirectoryInfo.MoveTo:将目錄(及其包含的内容)移動至一個新的目錄,也可用來重命名目錄;

DirectoryInfo.Delete:删除目錄(如果它存在的話)。如果要删除一個包含子目錄的目錄,要使用它的重載版本,以指定遞歸删除。

注意到了沒有?DirectoryInfo類少了一個CopyTo方法,不過我們可以通過遞歸來實作這個功能:

    /// 複制目錄到目标目錄

    /// &lt;param name="source"&gt;源目錄&lt;/param&gt;

    /// &lt;param name="destination"&gt;目标目錄&lt;/param&gt;

    public static void CopyDirectory(DirectoryInfo source, DirectoryInfo destination)

        // 如果兩個目錄相同,則無須複制

        if (destination.FullName.Equals(source.FullName))

            return;

        // 如果目标目錄不存在,建立它

        if (!destination.Exists)

            destination.Create();

        // 複制所有檔案

        FileInfo[] files = source.GetFiles();

            // 将檔案複制到目标目錄

            file.CopyTo(Path.Combine(destination.FullName, file.Name), true);

        // 處理子目錄

        DirectoryInfo[] dirs = source.GetDirectories();

        foreach (DirectoryInfo dir in dirs)

            string destinationDir = Path.Combine(destination.FullName, dir.Name);

            // 遞歸處理子目錄

            CopyDirectory(dir, new DirectoryInfo(destinationDir));

問題10:如何獲得計算機的所有邏輯驅動器;

解決方案:使用DriveInfo類(需要.NET 2.0)

DriveInfo.GetDrives():獲得計算機的所有邏輯驅動器,傳回類型為DriveInfo[]; 

問題11:如何擷取指定驅動器的資訊;

DriveInfo.Name:擷取驅動器的名稱(如C:\);

DriveInfo.DriveType:擷取驅動器的類型(如Fixed,CDRom,Removable,Network等);

DriveInfo.DriveFormat:擷取驅動器的格式(如NTFS,FAT32,CDFS,UDF等);

DriveInfo.IsReady:擷取驅動器是否已準備好,比如CD是否已放入CD驅動器,如果驅動器沒有準備好,通路其資訊會引發IOException類型異常;

DriveInfo.AvailableFreeSpace:擷取驅動器的可用空間;

DriveInfo.TotalFreeSpace:擷取驅動器總的可用空間,它與AvailableFreeSpace的不同在于AvailableFreeSpace會磁盤配額的設定;

DriveInfo.TotalSize:擷取驅動器總的空間;

DriveInfo.RootDirectory:獲得驅動器的根目錄(DirectoryInfo類型);

至此,我們已經了解了檔案和目錄相關的一些基本操作。

<b>檔案讀寫相關類介紹:</b>

<b>】</b>

<b>檔案讀寫操作涉及的類主要是:</b>

MarshalByRefObject 類:允許在支援遠端處理的應用程式中跨應用程式域邊界通路對象;

BinaryReader 類:用特定的編碼将基中繼資料類型讀作二進制值。

BinaryWriter 類: 以二進制形式将基元類型寫入流,并支援用特定的編碼寫入字元串。

Stream 類: 提供位元組序列的一般視圖。

FileStream類:公開以檔案為主的 Stream,既支援同步讀寫操作,也支援異步讀寫操作。

MemoryStream 類:建立其支援存儲區為記憶體的流。

BufferedStream 類:給另一流上的讀寫操作添加一個緩沖層。

TextReader 類:表示可讀取連續字元系列的閱讀器。

TextWriter 類:表示可以編寫一個有序字元系列的編寫器。

StreamReader 類:實作一個 TextReader,使其以一種特定的編碼從位元組流中讀取字元。

StreamWriter 類:實作一個 TextWriter,使其以一種特定的編碼向流中寫入字元。

StringReader 類:實作從字元串進行讀取的 TextReader。

StringWriter 類:實作一個用于将資訊寫入字元串的 TextWriter。該資訊存儲在基礎StringBuilder中。

在使用它們之前最好能了解它們的繼承關系,有助于作出最合适的選擇:

<b></b>

<b>另外還要注意一下FileInfo和File類的一些方法,如Create,CreateText,Open等,有時也會帶來友善。</b>

<b>     本文轉自My_King1 51CTO部落格,原文連結:</b><b>http://blog.51cto.com/apprentice/1360725</b><b>,如需轉載請自行聯系原作者</b>

繼續閱讀