在Windows操做系統中,存儲介質統稱爲驅動器,硬盤因爲能夠劃分爲多個區域,每個區域稱爲一個驅動器。.NET Framew ork提供DriveInfo類和 DriveType枚舉型,以方便在程序中直接使用驅動器。DriveInfo類的經常使用字段成員有DriveFormat(文件系統格式,如NTFS或FAT32)、DriveType(驅動器類型)、Name(驅動器名)、TotalSize(總空間)、TotalFreeSpace(得到驅動器可用空間)。經常使用的方法成員有GetDrives(得到可用驅動器列表)。windows
DriveType枚舉型的枚舉值有CDRom(光驅)、Fixed(硬盤)、Network(網絡驅動器)和Removeable(軟盤或U盤)等。例如,如下代碼能夠輸出每個硬盤驅動器的剩餘空間信息。數組
DriveInfo[] drivers = DriveInfo.GetDrives(); foreach(DriveInfo driver in drivers) { if(driver.DriveType == DriveType.Fixed && driver.DriveFormat == "NTFS") { Console.WriteLine("在{0}驅動器上還有{1}字節的剩餘空間。", driver.Name, driver.AvailableFreeSpace); } } Console.ReadLine();
爲了方便檢索文件,須要在驅動器中先建立目錄,而後把文件保存到這個目錄中。在Windows操做系統中,目錄又稱文件夾。每一個驅動器都有一個根目錄,使用」\」表示,如」C:\」表示C驅動器的根目錄。建立在根目錄中的目錄稱爲一級子目錄。在一級子目錄中建立的目錄稱爲二級子目錄,依此類推。文件系統的目錄結構是一種樹形結構。緩存
.NET Framework提供了Directory類和DirectoryInfo類,以方便在程序中直接操做目錄。網絡
Directory類的經常使用方法成員有CreateDirectory(建立新目錄)、Delete(刪除目錄)、Exists(判斷目錄是否存在)、Move(移動目錄)、GetFiles(得到目錄的文件列表)、GetDirectories(得到子目錄列表)等。數據結構
DirectoryInfo類的經常使用字段成員有Name(提取目錄名)、Exists(判斷目錄是否存在)、Parent(父目錄)、Root(根目錄)、MoveTo(移動目錄)、GetFiles(得到目錄的文件列表)、GetDirectories(得到子目錄列表)等。例如,如下代碼分別展示了Directory類和DirectoryInfo類的基本方法。異步
Directory.CreateDirectory(@"d:\C#程序設計"); if(Directory.Exists(@"d:\C#程序設計")) { Console.WriteLine("建立成功"); } Directory.Delete(@"d:\C#程序設計"); if (!Directory.Exists(@"d:\C#程序設計")) { Console.WriteLine("刪除成功"); } DirectoryInfo dir = new DirectoryInfo(@"d:\C#程序設計"); if (!dir.Exists) { dir.Create(); } else { Console.WriteLine("該目錄已經存在"); }
.NET Framework提供了File類和FileInfo類,以方便在程序中直接操做文件。File和FileInfo類位於System.IO命名空間,均可以用來實現建立、複製、移動、打開文件等操做。File類和FileInfo類與Directory類和DirectoryInfo類的工做方式類似。File類是一個靜態類,可直接調用其方法成員。FileInfo類不是靜態類,須要先建立實例。ide
(一)、文件類File函數
File類的經常使用方法ui
常 用 方 法編碼 |
介 紹 |
Open() |
打開文件 |
Create() |
建立文件 |
Copy() |
複製文件 |
Delete() |
刪除文件 |
Exists() |
判斷文件是否存在 |
Move() |
移動文件 |
Replace() |
替換文件 |
AppendAllText() |
新建文件並添加文本 |
ReadAllText() |
打開並讀取文本內容 |
下面經過一個示例演示File類的用法。
(1) 建立一個名爲FileCreate的控制檯應用程序項目
(2) 修改Program.cs文件中的Main方法的內容以下:
//設置所要建立文件的絕對路徑 string path = @"d:\test.txt"; //以路徑爲參數建立文件 File.Create(path);
代碼中變量path給出類文件的路徑,利用File類的Create方法建立類該文件。查看D盤根目錄,會有一個新的test.txt的文檔出現。
(二)、 文件信息類 FileInfo
文件信息類FileInfo與File類不一樣,它雖然也提供類建立、複製、刪除、移動和打開文件的方法,而且幫助建立FileStream對象,可是它提供的僅僅是實例方法。
FileInfo類經常使用字段
經常使用字段 |
介紹 |
Name |
提取文件名 |
Directory |
所屬目錄 |
Exists |
是否存在(繼承自父類FileSystemInfo) |
Extension |
文件擴展名 |
Length |
文件長度 |
IsReadOnly |
是否爲只讀 |
FileInfo類經常使用方法
經常使用方法 |
介紹 |
Open() |
打開文件 |
Create() |
建立文件 |
CopyTo() |
複製到新文件 |
Delete() |
刪除文件 |
MoveTo() |
移動文件 |
Replace() |
替換文件 |
EnCrypt() |
加密文件 |
Decrypt() |
解密文件 |
所以要使用FileInfo類,必須先實例化一個FileInfo對象。FileInfo類的經常使用方法與File類基本相同。
與文件類File和文件夾類Directory相比,文件信息類FileInfo和文件夾信息類DirectoryInfo具備其大部分功能。
* File類和Directory類適合對不一樣的對象進行單一的處理。此種特殊狀況下,靜態方法的調用速度比較快,不用進行實例化。
* FileInfo類和DirectoryInfo類適合用於對同一文件或文件夾進行多種操做的狀況。此種狀況下,實例化後的對象不須要每次都尋找文件,能夠直接對該文件進行操做。
(三)、 路徑
每一個驅動器包含一個或多個目錄,而每一個目錄又能夠包含一個或多個子目錄,目錄的結構爲樹形結構。一個文件只能保存在樹形結構的某個特定的目錄中,文件所在位置爲路徑。要檢索文件時,必須首先肯定文件的路徑。路徑由驅動器盤符、目錄名、文件名、文件擴展名和分隔符組成,有兩種種表示方法:一種是從驅動器的根目錄開始書寫,如C:\Windows\System32\notepad.exe,這種路徑稱爲絕對路徑;另外一種是從當前目錄位置開始書寫,如System32\notepad.exe(假設當前目錄爲C:\Windows),這種路徑稱爲相對路徑。
在C#中,使用文件和目錄路徑時要十分謹慎。C#將反斜槓」\」字符視做轉義符,所以當路徑表示爲字符串時,要使用兩個反斜槓表示,例如:
「C:\\Windows\\System32\\notepad.exe」
另外,C#容許在字符串前添加」@」標誌,以提示編譯器不要把」\」字符視做轉義符,而視做普通字符,例如:
@」C:\Windows\System32\notepad.exe」
.NET Framework提供了Path類,以幫助在程序中管理文件和目錄路徑,Path類位於System.IO命名空間,是一個靜態類,能夠用來操做路徑的每個字段,如驅動器盤符、目錄名、文件名、文件擴展名和分隔符等。Path類的經常使用字段成員有PathSeperator(路徑分隔符,如」;」)、DirectorySeparatorChar(目錄分隔符,如」\」)、VolumeSeparator(卷分隔符,如」:」)、AltDirectorySeparator(替換目錄分隔符,如」/」),經常使用的方法成員有GetDirectoryName(取目錄名)、GetFileName(取文件名)、GetExtension(取文件擴展名)、GetFullPath(取完整路徑)、GetTempPath(取操做系統的臨時文件路徑)等,例如,如下代碼表示提取並顯示路徑中的目錄名和文件名。
string path = @"c:\windows\System32\notepad.exe"; Console.WriteLine(Path.GetDirectoryName(path)); Console.WriteLine(Path.GetFileName(path));
其中,目錄名爲」C:\Windows\System32」,文件名爲」notepad.exe」。
在.NET Framework中,文件和流是有區別的。文件是存儲在磁盤上的數據集,它具備名稱和相應的路徑。當打開一個文件並對其進行讀/寫時,該文件就稱爲流(stream)。可是,流不只僅是指打開的磁盤文件,還能夠是網絡數據。.Net Framework容許在內存中建立流。此外,在控制檯應用程序中,鍵盤輸入和文本顯示都是流。流包括如下基本操做:
* 讀取(read):把數據從流傳輸到某種數據結構中,如輸出到字符數組中。
* 寫入(write):把數據從某種數據結構傳輸到流中,如把字節數組中的數據傳輸到流中。
* 定位(seek):在流中查找或從新定位當前位置。
(一)、操做流的類
1. Stream類
Stream類是全部流的抽象基類。Stream類的主要屬性有CanRead(是否支持讀取)、CanSeek(是否支持查找)、CanTimeout(是否能夠超時)、CanWrite(是否支持寫入)、Length(流的長度)、Position(獲取或設置當前流中的位置)、ReadTimeout(獲取或設置讀取操做的超時時間)、WriteTimeout(獲取或設置寫操做的超時時間),主要方法有BeginRead(開始異步讀操做),BeginWrite(開始異步寫操做)、Close(關閉當前流)、EndRead(結束異步讀操做)、EndWrite(結束異步寫操做)、Flush(清除流的全部緩衝區並把緩衝數據寫入基礎設備)、Read(讀取字節序列)、ReadByte(讀取一個字節)、Seek(設置查找位置)、Write(寫入字節序列)、WriteByte(寫入一個字節)。
2. FileStream、MemoryStream和BufferedStream類
文件流類FileStream以流的形式讀、寫、打開、關閉文件。另外,它還能夠用來操做諸如:管道、標準輸入/輸出等其餘與文件相關的操做系統句柄。
內存流MemoryStream類用來在內存中建立流,以暫時保持數據,所以有了它就無須在硬盤上建立臨時文件。它將數據封裝爲無符號的字節序列,能夠直接進行讀、寫、查找操做。
緩衝流BufferedStream類表示把流先添加到緩衝區,再進行數據的讀/寫操做。緩衝區是存儲區中用來緩存數據的字節塊。使用緩衝區能夠減小訪問數據時對操做系統的調用次數,加強系統的讀/寫功能。
注意,FileStream類也有緩衝功能,在建立FileStream類的實例時,只須要指定緩衝區的大小便可。
3. StreamReader和StreamWriter類
流讀取器StreamReader類用來以一種特定的編碼(如:UTF-8)從字節流中讀取字符,流寫入器StreamWriter類用來以一種特定的編碼(如:UTF-8)向流中寫入字符。StreamReader和StreamWriter類通常用來操做文本文件。
4. BinaryReader和BinaryWriter類
BinaryReader類用特定的編碼將基元數據類型讀做二進制。BinaryWriter類以二進制形式將基元類型寫入流,並支持用特定的編碼寫入字符串。
5. 文件流類 FileStream
文件流類FileStream公開了以文件爲主的Stream,既支持同步讀/寫操做,也支持異步讀/寫操做,FileStream類的特色是操做字節和字節數組。這種方式不適合操做用字符數據構成的文本文件,適合處理非文本文件。FileStream類提供了對文件的低級而複雜的操做,所以可以實現更多高級的功能。
下面演示FileStreamWriter類的基本用法:
//要寫入文件的字符數組 char[] m_cDataWrite = new char[100]; //包含要寫入該流的數據的緩衝區 byte[] m_bDataWrite = new byte[100]; try { //建立d:\file.txt的FileStream對象 FileStream m_FileStream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate); //將要寫入的字符串轉換成字符數組 m_cDataWrite = "test filestream".ToCharArray(); //經過UTF-8編碼方法將字符數組轉成字節數組 Encoder m_Enc = Encoding.UTF8.GetEncoder(); m_Enc.GetBytes(m_cDataWrite, 0, m_cDataWrite.Length, m_bDataWrite, 0, true); //設置流當前位置爲文件開始位置 m_FileStream.Seek(0, SeekOrigin.Begin); //將字節數組中的內容寫入文件 m_FileStream.Write(m_bDataWrite, 0, m_bDataWrite.Length); if (m_FileStream != null) { //清除此流的緩衝區,使得全部緩衝的數據都寫入到文件中 m_FileStream.Flush(); m_FileStream.Close(); } } catch (Exception ex) { Console.WriteLine("There is an IOException"); Console.WriteLine(ex.Message); } Console.WriteLine("Write to File Succeed!");
代碼中首先給出了文件夾的路徑,利用Write方法向文件中寫入部分字符串。
下面演示FileStreamReader類的基本用法:
//要寫入文件的字符數組 char[] m_cDataWrite = new char[100]; //包含要寫入該流的數據的緩衝區 byte[] m_bDataWrite = new byte[100]; try { //建立d:\file.txt的FileStream對象 FileStream m_FileStream = new FileStream(@"d:\file.txt", FileMode.Open); //設置流當前位置爲文件開始位置 m_FileStream.Seek(0, SeekOrigin.Begin); //將文件的內容存到字節數組中(緩存) m_FileStream.Read(m_bDataWrite, 0, 100); } catch (Exception ex) { Console.WriteLine("There is an IOException"); Console.WriteLine(ex.Message); } //經過UTF-8編碼方法將字符數組轉換成字符數組 Decoder m_Dec = Encoding.UTF8.GetDecoder(); m_Dec.GetChars(m_bDataWrite, 0, m_bDataWrite.Length, m_cDataWrite, 0); Console.WriteLine("Read from file Succeed!"); Console.WriteLine(m_cDataWrite);
代碼中首先給出了文件夾的路徑,利用Read方法從文件中讀取了部分字符串。
6. StreamWriter和StreamReader類
應用FileStream類須要許多額外的數據類型轉換操做,十分影響效率。StreamWriter類容許直接將字符和字符串寫入文件。下面演示其用法:
try { //保留文件現有數據,以追加寫入的方式打開d:\file.txt文件 StreamWriter m_SW = new StreamWriter(@"d:\file.txt", true); //向文件寫入新字符串,並關閉StreamWriter m_SW.WriteLine("Another File Operation Method"); m_SW.Close(); } catch (Exception ex) { Console.WriteLine("There is an IOException"); Console.WriteLine(ex.Message); } StreamWriter類提供了另外一種從文件中讀取數據的方法,下面演示其用法: try { //以絕對路徑方式構造新的StreamReader對象 StreamReader m_SR = new StreamReader(@"d:\file.txt"); //用ReadToEnd方法將d:\file.txt中的數據所有讀入到字符串m_Data中,並關閉StreamReader string m_Data = m_SR.ReadToEnd(); m_SR.Close(); Console.WriteLine(m_Data); } catch (Exception ex) { Console.WriteLine("There is an IOException"); Console.WriteLine(ex.Message); }
7. BinaryReader和BinaryWriter類
BinaryWriter類是除了FileStream和StreamWriter類以外另外一種向文件寫入數據的方式,與以前兩種方式不一樣,BinaryWriter類將基礎數據(如:字符串)以二進制形式寫入文件流中,並支持用特定的編碼寫入。下面演示其用法:
FileStream m_FS = new FileStream(@"d:\data.dat", FileMode.Create); //經過文件流建立相應的BinaryWriter BinaryWriter m_BW = new BinaryWriter(m_FS); for(int i = 0; i < 11; i++) { //向d:\data.dat中寫入數據 m_BW.Write((int)i); } m_BW.Close(); m_FS.Close();
代碼中首先給出了文件夾的路徑,利用BinaryWriter類的Write方法向文件中寫入部分二進制字符。該文件是以二進制存儲的,所以用記事本打開時,將沒法觀察到正確的字符,必須使用支持二進制的文本閱讀器。
BinaryReader類是和BinaryWriter類相對應的二進制數據讀取類。它用特定的編碼將基元數據類型(如:字符串類型)讀做二進制值。
FileStream m_FS = new FileStream(@"d:\data.dat", FileMode.Open, FileAccess.Read); //經過文件流建立相應的BinaryReader BinaryReader m_BR = new BinaryReader(m_FS); //從d:\data.dat中讀取數據 for(int i = 0; i < 11; i++) { Console.WriteLine(m_BR.ReadInt32()); } m_BR.Close(); m_FS.Close(); Console.ReadLine();
代碼中首先給出了文件夾的路徑。利用BinaryReader類的ReadInt32方法從文件中讀取了全部的二進制字符,並將其讀爲整數,便於輸出。
5、 綜合應用
(一)、建立日誌文件
日誌文件的做用是記錄程序運行事件。一般使用文本文件保存數據。日誌文件須要程序自動建立,並在指定的事件發生時,使用特定的格式把事件的相關數據記錄到日誌文件中。
一、技術要點
* 建立FileStream類實例時,可以經過該類構造函數的參數,指定打開文件的方式和讀/寫訪問的方式。經過指定打開方式,實現日誌文件的自動建立。
* 使用StreamWriter類實例寫入文件時,由於部分數據可能因爲系統緩慢而未能及時寫入,因此在全部的寫入操做完成後,須要調用Flush方法將緩衝區的文件內容更新到日誌文件中。
* 使用StreamWriter類實例寫入文件時,寫入的方式與Console相似,可使用WriteLine向文件中寫入一行文本數據。
2 、實現代碼
const string _FILENAME = @"..\..\logfile.txt"; static void Main() { //從指定的目錄以打開或者建立的形式讀取日誌文件 using (FileStream fs = new FileStream(_FILENAME, FileMode.OpenOrCreate, FileAccess.Write)) { //建立日誌文件的寫入流 StreamWriter sw = new StreamWriter(fs); //向日志文件寫入日誌信息 Log("日誌文件建立成功", sw); //關閉日誌文件寫入流 sw.Close(); Console.WriteLine("日誌文件已建立"); } //讀取並顯示日誌文件 using (StreamReader sr = new StreamReader(_FILENAME, Encoding.UTF8)) { string strContent = sr.ReadToEnd(); sr.Close(); Console.WriteLine(strContent); } Console.ReadLine(); } static void Log(String message, TextWriter tw) { tw.Write("Log Entry:"); tw.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString()); tw.WriteLine(" :"); tw.WriteLine(" :{0}", message); tw.WriteLine("----------------------------------"); //將緩衝區中的內容更新到日誌文件中 tw.Flush(); }
三、 源程序解讀
(1)程序引用了System.IO命名空間,在程序頭部應添加對該命名空間的引用。
(2)程序中定義了表示文件路徑的常量_FILENAME
(3)在建立FileStream類實例時,使用FileMode.OpenOrCreate模式,即文件不存在時就建立,存在時就打開已存在的文件。
(二)、對日誌文件的讀/寫操做
日誌文件的讀/寫和文本文件的讀/寫方法基本相同,日誌文件除了使用StreamReader類和StreamWriter類的實例進行讀/寫外,還有一些記錄事件的要求。例如,在寫入數據時使用追加的方式、控制日誌文件的大小等。
一、 技術要點
* 使用FileInfo類實例獲取日誌文件的大小,實現當日志文件的大小超出指定範圍時清空日誌數據的功能。並使用該類實例的OpenWrite方法,建立FileStream類實例進行寫入文件的操做,實現日誌文件的自動建立功能。
* 使用StreamWriter類中定義的Seek方法,將寫入位置移動到文件末尾,實現將數據以追加方式寫入日誌文件的功能。
* 使用StreamReader類中定義的Peek方法,判斷讀取器是否已經讀到日誌文件的末尾。
二、 實現代碼
//表示日誌文件路徑及文件名稱的字符串 const string FILENAME = @"..\..\logfile.txt"; static void Main(string[] args) { //寫入日誌信息 WriteLogFile(FILENAME, "日誌信息一"); //讀取日誌文件 Console.WriteLine(ReadLogFile(FILENAME)); Console.ReadLine(); } static string ReadLogFile(string FileNameWithPath) { //從指定的目錄以打開或建立的形式讀取日誌文件 FileStream fs = new FileStream(FileNameWithPath, FileMode.OpenOrCreate, FileAccess.Read); //定義輸出字符串 StringBuilder output = new StringBuilder(); //初始化該字符串的長度爲0 output.Length = 0; //爲上面建立的文件流建立讀取數據流 StreamReader read = new StreamReader(fs); //設置當前流的起始位置爲文件流的起始點 read.BaseStream.Seek(0, SeekOrigin.Begin); //讀取文件 while(read.Peek() > -1) { //取文件的一行內容並換行 output.Append(read.ReadLine() + "\n"); } //關閉釋放讀數據流 read.Close(); //返回讀到的日誌文件內容 return output.ToString(); } static void WriteLogFile(string FileNameWithPath, string Message) { //定義文件信息對象 FileInfo finfo = new FileInfo(FileNameWithPath); //判斷文件是否存在以及是否大於2K if(finfo.Exists && finfo.Length > 2048) { //刪除該文件 finfo.Delete(); } //建立只寫文件流 using(FileStream fs = finfo.OpenWrite()) { //根據上面建立的文件流建立寫數據流 StreamWriter w = new StreamWriter(fs); //設置寫數據流的起始位置爲文件流的末尾 w.BaseStream.Seek(0, SeekOrigin.End); //寫入"Log Entry:" w.Write("Log Entry:"); //寫入系統的當前時間並換行 w.Write("{0} {1} \r\n", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString()); //寫入日誌內容並換行 w.Write(Message + "\r\n"); //寫入-------------------------並換行 w.Write("----------------------\r\n"); //清空緩衝區內容,並把緩衝區內容寫入基礎流 w.Flush(); w.Close(); }
運行結果以下:
Log Entry:14:26:09 2017年5月1日
日誌信息一
3 、源程序解讀
(1)本示例程序使用寫日誌文件的WriteLogFile方法向文件中寫入一條信息數據,再經過讀取日誌文件的ReadLogFile方法將日誌文件的數據顯示出來。本示例程序的流程圖以下所示: 圖1 對日誌文件讀/寫操做示例程序流程圖
(2)在寫入日誌文件的WriteLogFile方法中,首先打開並判斷日誌文件的大小是否超出了指定的尺寸。若是超出了指定的尺寸,就先將日誌文件刪除。而後經過FileInfo類實例的OpenWrite方法建立只寫文件流,向該流中寫入日誌數據。
(3)在讀取日誌文件的ReadLogFile方法中,首先建立一個StringBuilder類的實例,用來獲取日誌文件中的文本數據。接着使用StreamReader類定義的BaseStream屬性中的Seek方法,將讀取器位置定位在流的開始位置,而後循環讀取日誌文件中的文本數據,並追加到StringBuilder類實例中,讀取過程當中,經過StreamReader類中定義的Peek方法判斷是否讀到文件末尾。
(三)、複製文件
靜態File類中提供了許多操做文件的方法,使用Copy方法複製文件是比較常見的一種操做,調用Copy方法時,可使用overwrite參數指定是否覆蓋文件。
一、 技術要點
* 使用靜態類File的Exists方法判斷文件是否存在。
* 使用靜態類File的Copy方法實現複製文件的功能,當文件存在時,經過指定override參數覆蓋原有文件。
* 複製文件是系統操做,爲了保證程序的穩定性,在複製文件的過程當中須要捕獲並處理異常。
二、 實現代碼
//源文件路徑及文件名 const string SOURCEFILENAME = @"..\..\myfile.txt"; //目標文件路徑及文件名 const string DESTINATIONFILENAME = @"..\..\result.txt"; static void Main(string[] args) { try { //判斷源文件是否存在 if(!File.Exists(SOURCEFILENAME)) { Console.WriteLine("找不到源文件"); } else if (File.Exists(DESTINATIONFILENAME)) { Console.Write("目標文件已經存在,是否覆蓋?(Y/N)"); if(Console.ReadKey(false).Key == ConsoleKey.Y) { //覆蓋文件 File.Copy(SOURCEFILENAME, DESTINATIONFILENAME, true); Console.WriteLine("複製文件完成"); } else { Console.WriteLine("取消複製文件"); } } else { //直接複製 File.Copy(SOURCEFILENAME, DESTINATIONFILENAME); Console.WriteLine("複製文件完成"); } } catch (Exception) { Console.WriteLine("複製文件失敗"); } Console.ReadLine(); }
3 、源程序解讀
(1)本示例使用File靜態類的方法實現文件的複製操做。首先判斷源文件是否存在,若是源文件不存在,不做任何處理就返回。接着判斷目標文件是否存在,若是目標文件不存在,就直接複製文件,不然就詢問是否覆蓋現有的目標文件,當用戶選擇覆蓋時,使用源文件覆蓋目標文件。
(2)在複製文件的方法調用時,將複製文件的代碼放在一個try...catch結構中,以便捕獲並處理複製文件時出現的異常。
(3)程序執行後,將程序文件所在目錄下生成一個名爲」result.txt」的文本文件。內容與」myfile.txt」文件一致。