文章目錄
- 一、FileStream和StreamWriter理解
- 1.1、具體關系解析
- 1.2、類比理解
- 1.3、總結
- 1.4、示例代碼
- 1.5、 WriteLine()和 Write()的區別
- 1.6、 StreamWriter.Close的作用
- 二、
一、FileStream和StreamWriter理解
在 C# 中,StreamWriter
和 FileStream
是 協作關系,二者共同完成文件的文本寫入操作,但職責不同。簡單來說:
FileStream
負責底層的 字節級文件操作(如打開、讀取、寫入字節),而 StreamWriter
基于 FileStream
提供 文本編碼轉換和便捷的文本寫入功能(如直接寫入字符串、換行等)。
1.1、具體關系解析
-
依賴關系
StreamWriter
的構造函數需要接收一個Stream
類型的參數(FileStream
是Stream
的子類),即StreamWriter
必須依賴一個底層流(如FileStream
)才能工作。
例:new StreamWriter(aFile)
中,aFile
(FileStream
)是StreamWriter
的“數據源/目標”。 -
功能分工
FileStream
:處理與操作系統交互的底層細節,比如:- 打開文件并獲取文件句柄
- 以字節(
byte
)為單位讀寫數據 - 控制文件的打開模式(
FileMode
)、訪問權限(FileAccess
)、共享模式(FileShare
)等。
StreamWriter
:在FileStream
之上封裝了文本處理邏輯,比如:- 將字符串自動編碼為字節(默認 UTF-8,可指定編碼)
- 提供
WriteLine()
等便捷方法(自動處理換行符\r\n
) - 內部維護緩沖區,減少頻繁的底層 IO 操作,提升性能。
-
生命周期關聯
當StreamWriter
被釋放(如using
語句結束)時,會自動刷新緩沖區并關閉其依賴的FileStream
(除非構造時指定leaveOpen: true
)。
例:若希望釋放StreamWriter
后仍保留FileStream
用于其他操作,可這樣寫:using (FileStream aFile = new FileStream("Log.txt", FileMode.OpenOrCreate)) {// leaveOpen: true 表示釋放 StreamWriter 時不關閉 FileStreamusing (StreamWriter sw = new StreamWriter(aFile, leaveOpen: true)){sw.WriteLine("Hello");}// 此時 aFile 仍可繼續使用(如讀取字節) }
1.2、類比理解
可以把二者的關系類比為“水管”和“水龍頭”:
FileStream
是 水管:負責連接水源(文件),提供原始的水流(字節)傳輸通道。StreamWriter
是 帶過濾功能的水龍頭:安裝在水管上,將原始水流(字節)轉換為符合需求的“飲用水”(字符串),并提供便捷的開關(寫入方法)。
1.3、總結
FileStream
是底層字節流,處理文件的物理操作;StreamWriter
是高層文本包裝器,依賴FileStream
實現字符串到字節的轉換和便捷寫入。- 二者結合使用,既利用了
FileStream
的底層控制能力,又通過StreamWriter
簡化了文本處理。
1.4、示例代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;namespace StreamWrite
{class Program{static void Main(string[] args){try{FileStream aFile = new FileStream("Log.txt", FileMode.OpenOrCreate);StreamWriter sw = new StreamWriter(aFile);bool truth = true;// Write data to file.sw.WriteLine("Hello to you.");sw.WriteLine("It is now {0} and things are looking good.",DateTime.Now.ToLongDateString());sw.Write("More than that,");sw.Write(" it's {0} that C# is fun.", truth);sw.Close();}catch(IOException e){Console.WriteLine("An IO exception has been thrown!");Console.WriteLine(e.ToString());Console.ReadLine();return;}}}
}
1.5、 WriteLine()和 Write()的區別
sw.WriteLine("Hello to you.");sw.WriteLine("It is now {0} and things are looking good.",DateTime.Now.ToLongDateString());sw.Write("More than that,");
在 C# 的 StreamWriter
類中,WriteLine()
和 Write()
是兩個常用的寫入方法,它們的核心區別在于 是否自動添加換行符。以下是詳細對比:
一、核心區別
方法 | 是否添加換行符 | 寫入后光標位置 | 示例代碼效果 |
---|---|---|---|
WriteLine() | ? 自動添加 | 移至下一行開頭 | sw.WriteLine("A"); sw.WriteLine("B"); → 文件內容:A B |
Write() | ? 不添加 | 留在當前行末尾 | sw.Write("A"); sw.Write("B"); → 文件內容:AB |
二、示例對比
假設你有以下代碼:
using (StreamWriter sw = new StreamWriter("test.txt"))
{sw.Write("第一行");sw.WriteLine("第二行");sw.Write("第三行");sw.WriteLine("第四行");
}
生成的 test.txt
文件內容為:
第一行第二行
第三行第四行
三、使用場景建議
-
逐行寫入文本(如日志、CSV):
使用WriteLine()
,例如:sw.WriteLine("Name, Age"); sw.WriteLine("Alice, 30"); sw.WriteLine("Bob, 25");
-
格式化輸出(如拼接字符串):
使用Write()
配合WriteLine()
,例如:sw.Write("Total: "); sw.WriteLine(100.50); // 輸出:Total: 100.50
-
手動控制換行:
使用Write()
并顯式添加換行符(\n
或Environment.NewLine
),例如:sw.Write("第一部分內容\n"); // 等效于 sw.WriteLine("第一部分內容"); sw.Write("第二部分內容" + Environment.NewLine); // 跨平臺換行符
四、性能差異
兩者的性能差異極小,可忽略不計。但在大量寫入時:
WriteLine()
可能略微慢于Write()
(多一次換行符寫入)。- 建議結合
BufferedStream
提升整體性能:using (FileStream fs = new FileStream("test.txt", FileMode.Create)) using (BufferedStream bs = new BufferedStream(fs, 8192)) // 8KB 緩沖區 using (StreamWriter sw = new StreamWriter(bs)) {// 批量寫入 }
五、注意事項
-
換行符的平臺差異:
- Windows 默認使用
\r\n
(回車+換行)。 - Linux/macOS 使用
\n
(換行)。 WriteLine()
會根據當前操作系統自動選擇換行符(通過Environment.NewLine
)。
- Windows 默認使用
-
與
Console.WriteLine()
的類比:StreamWriter
的WriteLine()
和Console.WriteLine()
邏輯一致,只是輸出目標不同(文件 vs 控制臺)。
六、總結
- 用
WriteLine()
:當需要每行獨立時(如日志、配置文件)。 - 用
Write()
:當需要自定義格式或拼接內容時(如 JSON、HTML)。 - 混用:當需要靈活控制換行位置時(如表格輸出)。
合理選擇方法可以讓代碼更簡潔、輸出更易讀。
1.6、 StreamWriter.Close的作用
在 C# 中,sw.Close()
的作用是 釋放 StreamWriter
占用的系統資源(如文件句柄、網絡連接等)。如果不調用 Close()
,會導致以下問題:
一、不調用 Close()
的后果
-
資源泄漏
- 文件句柄不會立即釋放,其他程序無法訪問該文件(如無法刪除或修改)。
- 若頻繁創建
StreamWriter
而不關閉,可能耗盡系統資源(如文件句柄上限)。
-
數據丟失風險
StreamWriter
有 緩沖區(默認 4KB),數據會先寫入緩沖區,而非直接寫入文件。- 若不調用
Close()
或Flush()
,緩沖區中的數據可能 不會被寫入文件。
-
異常處理不完善
- 若寫入過程中發生異常,
Close()
可能不會被執行,導致資源無法釋放。
- 若寫入過程中發生異常,
二、Close()
的底層邏輯
Close()
方法實際上做了兩件事:
Flush()
:將緩沖區中的數據強制寫入文件。Dispose()
:釋放非托管資源(如文件句柄),并標記對象已銷毀。
三、推薦替代方案:using
語句
C# 提供了 using
語句,它會自動調用 Dispose()
方法(等價于 Close()
),即使發生異常也能確保資源釋放。
示例對比:
// 不使用 using(需手動 Close())
StreamWriter sw = new StreamWriter("test.txt");
sw.WriteLine("Hello");
sw.Close(); // 必須顯式調用,否則資源泄漏// 使用 using(自動釋放資源)
using (StreamWriter sw = new StreamWriter("test.txt"))
{sw.WriteLine("Hello");// 無需調用 Close(),using 塊結束時自動釋放
}
四、為什么示例代碼中不調用 Close()
仍“正常”?
-
程序退出時系統回收資源
若程序立即退出,操作系統會強制釋放文件句柄,但這是不可控的行為,不推薦依賴。 -
緩沖區自動刷新
- 緩沖區滿時(默認 4KB)會自動刷新。
- 若寫入的數據量很小(如示例中的幾行文本),可能未填滿緩沖區,導致數據丟失。
五、最佳實踐
-
永遠使用
using
語句
避免手動調用Close()
,讓using
自動管理資源。 -
顯式調用
Flush()
(可選)
若需要立即寫入數據(如實時日志),可調用Flush()
:using (StreamWriter sw = new StreamWriter("log.txt")) {sw.WriteLine("重要日志");sw.Flush(); // 立即寫入文件,不等待緩沖區滿 }
-
處理大文件時增大緩沖區
通過構造函數調整緩沖區大小(如 64KB),減少 IO 次數:using (FileStream fs = new FileStream("large.txt", FileMode.Create)) using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8, 65536)) {// 寫入大量數據 }
六、總結
Close()
的作用:釋放資源并確保數據寫入文件。- 不調用的風險:資源泄漏、數據丟失。
- 推薦方案:使用
using
語句替代手動Close()
,提升代碼安全性和簡潔性。