文件流
一、流的概述
要完成文件的讀寫操作,就必須了解C#中另外一個重要的概念——流(Stream)
C#中流的概念可以和生活中的流相對應。在生活中有水流和電流,首先要有一個源頭,還需要有傳輸的管道,
水流有河道、水管作為傳輸管道,電流有電線,而這些流都會有一個目的,就是它的流向。C#的流也需要源頭——文件、數據流入流出管道以及數據的訪問。
1、輸出流和輸入流
.Net Framework中進行的所有輸入、輸出工作都需要用到流。
1、輸出流:當向某些外部目標寫入數據時,就要用到輸出流。
2、輸入流:用於將數據讀到程序訪問的內存或變量中。
在程序的控制台中的可以理解為:
輸出流:控制台程序中,將信息從程序中輸出的處理:Console.WriteLine();
輸入流:通過用戶鍵盤來輸入到程序當中處理:Console.ReadLine();
2、文件讀寫,常用的三個類
對於文件讀寫,常見的三個類:
1、FileStream(文件流):這個類主要用於在二進制文件中讀寫二進制數據——也可以使用它讀寫任何文件。
2、StreamWriter(流寫入器)和StreamReader(流讀取器):這二個類是專門用來讀寫文本文件的。
二、FileStream對象
### 1、FileStream對象的二種重載
FileStream對象表示在磁盤或網絡路徑上指向文件的流。這個類提供了在文件中讀寫字節的方法。
有多種方法可以創建FileStream對象,FileStream類的構造函數有很多的重載版本,最簡單的重載版本僅帶有二個參數,即文件路徑和FileModel枚舉值。
1.1、第一種重載:
FileStream aFile = new FileStream( 文件路徑 , FileMode.成員值);
FileModel的枚舉成員:
成員值: | 文件存在: | 文件不存在: |
---|---|---|
Append | 打開文件,流指向文件的末尾,只能與枚舉FileAccess.Write聯合使用 | 創建一個新文件。只能與枚舉FileAccess.Write聯合使用 |
Create | 刪除該文件,然后創建新文件 | 創建新文件 |
CreateNew | 拋出異常 | 創建新文件 |
Open | 打開現有文件,流指向文件的開頭 | 拋出異常 |
OpenOrCreate | 打開現有文件,流指向文件的開頭 | 創建新文件 |
Truncate | 打開現有文件,清楚其內容。流指向文件的開頭,保留文件的初始創建日期。 | 拋出異常 |
1.2、第二種重載:
FileStream aFile = new FileStream( 文件路徑, FileMode.成員值, FileAccess.成員值);
FileAccess的枚舉成員:
成員值: | 說明: |
---|---|
Read | 打開文件,用於只讀 |
Write | 打開文件,用於只寫 |
ReadWrite | 打開文件,用於讀寫 |
在FileAccess構造函數不使用FileAccess枚舉參數的版本中,使用默認值FileAccess.ReadWrite。
File和FileInfo類中都提供了OpenRead()和OpenWrite()方法,使程序更易於創建FileStream對象。前者打 開了只讀訪問的文件,后者只允許寫入文件。
這些都提供了快捷方式,因此不一定要以FileStream構造函數的參數形式提供前面所有的信息。例如,下面的代碼行打開了用於只讀訪問的Data.txt文件。
FileStream aFile=File.OpenRead(@“C:\Data.txt”);
或者
FileInfo aFileInfo=new FileInfo(@“C:\Data.txt”);
FileStream aFile=afileInfo.OpenRead();
2、使用FileStream讀取數據和寫入數據
使用FileStream類讀取數據並不容易,這是因為FileStream類只能處理原始字節(Raw Byte)。
FileStream對象的Read()方法是從FileStream對象所指向的文件訪問數據的主要手段。這個方法從文件中讀取數據,再把數據寫入一個字節數組。
該方法有三個參數:第一個參數是傳入的字節數組,用以接收FileStream對象中的數據。第二個參數是字節數組中開始寫入數據的位置。通常是0,表示從數組開端開始放置讀入的字節。最后一個參數指定從文件中讀出多少字節。
2.1、讀取數據:
在編寫程序代碼前,需導入Sysytem.IO命名空間。此應用程序打開了磁盤上某個文件,用於讀取其中的部分數據。首先,通過實例化一個FileStream的對象,將流指向這個文件。
這可以通過:
FileInfo aFileInfo =new FileInfo(@"C:\My Document\ReadMe1.txt");
FileStream aFileInfo =aFileInfo.OpenRead();
步驟:創建FileStream對象,並指向文件流——得到文件大小(字節單位)——創建一個相同大小的字節數組——將文件的字節內容讀到數組中——將數組中字節轉為字符——輸出顯示——關閉流
/// <summary>
/// 讀取數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
//以只讀方式創建FileStream對象
FileStream afile = new FileStream(@"C:\My Document\ReadMe1.txt",FileMode.OpenOrCreate);
//得到文件的長度/大小
long length = afile.Length;
//使用文件的長度創建一個字節數組。
byte[] Buffers = new byte[length];
//將流中的數據的字節內容讀到字節數組中
afile.Read(Buffers, 0, Buffers.Length);
//將讀到的數據進行轉碼,轉為字符串
string content = Encoding.Default.GetString(Buffers, 0, Buffers.Length);
//將字符串在文件框中顯示
richTextBox1.AppendText(content);
//關閉流對象,釋放文件引用。
afile.Close();
}
2.2、寫入數據:
步驟:創建FileStream對象,並指向文件流——聲明一個數組是寫入數據字節的2倍——使用Encoding類的GetBytes()方法將字符串中的一組字符編碼到字節數組中,(1、編碼的字符集的字符串,2、表明第一個編碼的字符的索引,3、要編碼的字符的數量,4、表明要包含所產生的字節序列的字節數組,5、開始寫入所產生的字節序列索引位置)
/// <summary>
/// 寫入數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
//創建一個寫文件的文件流對象
FileStream aFile = new FileStream(@"C:\My Document\ReadMe1.txt",FileMode.OpenOrCreate, FileAccess.Write);
//創建字節數組
byte[] buffers;
//獲取傳入聞見的字符串
string content = richTextBox1.Text;
//為字節數組分配字符串
//可能會包含中文,可以將長度設為字符串長度的二倍
buffers = new byte[content.Length * 2];
//將字符串轉成字節放入字節數組中
Encoding.Default.GetBytes(content, 0, content.Length, buffers, 0);
//將字節數組寫入文件中
aFile.Write(buffers, 0, buffers.Length);
//關閉流對象,釋放文件引用。
aFile.Close();
}
三、StreamWrite和StreamReader對象
1、StreamWriter對象
StreamWriter對象只能用於寫入文件(或另一個流),StreamWriter類的構造方法有很多版本。最常用的有以下三種。
(1) StreamWriter sw=new StreamWriter(@ “C:\test.txt”);
將使用UTF-8的編碼方式創建StreamWriter對象,.NET把這種編碼設置為默認的編碼方式。
(2) StreamWriter sw=new StreamWriter(@ “C:\test.txt”, true);
在這個構造函數中,第二個參數是bool類型,表示文件是否以追加的方式打開。
(3) StreamWriter sw=new StreamWriter(@ “C:\test.txt”,true,Ecoding.ASCII);
在第三個函數中,第三個參數可以指明要使用的編碼方式ASCII來創建StreamWriter對象。但不能僅以文件名和編碼方式來創建對象。
當然,也可以將StreamWriter關聯到一個文件流上,以獲得打開文件的更多控制選項。例如以下代碼。
FileStream fs=new FileStream(@“C:\1.txt”,FileMode.Append,FileAccess.Write);
StreamWriter sw=new StreamWriter(fs);
StreamWriter對象有兩個方法來完成向文件或流中寫入數據的功能。
WriteLine()方法:一次寫入一行文本,流會自動把回車符合換行符添加到文本的末尾。
Write()方法:向流或文件中寫入文本,但不會在末尾添加回車和換行符。
StreamWriter對象和FileStream對象一樣,功能執行完畢后要使用Close()方法關閉以釋放資源。
2、StreamReader對象
StreamReader對象用於讀取文本文件。用某些方式構造StreamReader對象要比構造FileStream對象更簡單,因為使用StreamReader時不需要FileStream的一些選項。特別是不需要模式和訪問類型,因為它只能執行讀取操作。
StreamReader類的構造方法的版本比較多,最簡單的構造函數只帶一個文件名參數。
StreamReader sr=new StreamReader(@“C:\test.txt”);
StreamReader sr=new StreamReader(@“C:\test.txt”,Encoding.UTF8);
也可以把StreamReader關聯到FileStream對象上。例如以下代碼。
FileStream fs=new FileStream(@ “C:\test.txt”,FileMode.Open,FileAccess.Read);
StreamReader sr=new StreamReader(fs);
StreamReader對象讀取數據的方法主要有三個。
(1) Read()方法:此方法每次讀取一個字符,返回的是代表這個字符的一個正數,當獨到文件末尾時返回的是-1。
(2) ReadLine()方法:此方法每次讀取流中的一行數據,但不包括回車和換行符。當讀到文件末尾將返回null。
(3) ReadToEnd()方法:此方法一次性讀取文件中的所有數據。
3、使用StreamWriter對象寫入數據和StreamReader對象讀取數據
3.1、StreamWriter對象寫入數據
//讀取數據
private void button1_Click(object sender, EventArgs e)
{
//創建StreamReader對象
//編碼方式和寫入數據時保持一致
StreamReader sr = new StreamReader(@"C:\My Document\ReadMe1.txt", Encoding.Default);
//利用StreamReader對象的ReadToEnd()方法讀取文件中所有數據
richTextBox1.Text = sr.ReadToEnd();
//關閉StreamReader對象以釋放資源
sr.Close();
}
3.2、StreamReader對象讀取數據
//寫入數據
private void button2_Click(object sender, EventArgs e)
{
//創建StreamWriter對象
StreamWriter sw = new StreamWriter(@"C:\My Document\ReadMe1.txt", true, Encoding.Default);
//獲取輸入數據的文件並放入數組
string[] data = richTextBox1.Lines;
//遍歷字符串數組
foreach (string line in richTextBox1.Lines)
{
//將文本通過StreamWriter對象逐行寫入文件
sw.WriteLine(line);
}
//關閉StreamWriter對象以釋放資源
sw.Close();
}
四、總結
1、如果要對文件的內容進行讀寫,就需要用到流。
2、FileStream只能處理原始字節(Raw Byte)。處理原始字節的功能使FileStream類可以用於任何數據文件,而不僅僅是文本文件。通過讀取字節數據,FileStream對象可以用於讀取圖像和聲音的文件。這種靈活性的代價是,不能使用FileStream對象直接讀入字符串,需要將字節數組轉換為字符數組或者字符串。
3、雖然直接操作FileStream對象可以讀取和顯示文本文件,但是操作字節數組比較麻煩。如果知道某個文件包含文本,通常就可以使用StreamWriter和StreamReader類更方便的對這些文件進行寫入和讀,而不是FileStream對象。這是因為這些類工作的級別比較高,特別適合於讀寫文本。它們執行的方法可以根據流的內容,自動檢測出停止讀取文本較方便的位置。