重學c#系列—— IO流[三十四]
前言
簡單介紹一下io流。
以前寫過兩篇,里面是java 語言寫的,簡單介紹了一下io流,這里是對io流的整理。
http://www.qzems.com/aoximin/p/12007925.html
http://www.qzems.com/aoximin/p/12044270.html
這里說一下一個經驗,僅獻給入門的人。
剛寫代碼進行io流讀取或者寫入的時候,有一個思維去考慮這個io流是怎么從磁盤讀取的或者怎么從內存讀取的,
這個想法是沒錯的,但是不是應用層面考慮的東西,是操作系統和硬件的結合(操作系統篇會介紹全面),這會使人腦復雜,下面請以應用層面考慮問題。
正文
在io流中有幾個概念必須知道:
-
字符流
-
字節流
-
節點流
-
處理流
如果不清楚這些概念,那么你就需要看完這一篇回憶一下以前的基礎。
在java中,比如一個文件的讀取,分為FileInputStream 和 FileOutputStream。
但是在c# 是這樣設計的,文件流就是文件流, 沒有把輸入和輸出分開。
但是一般情況下,我們要么讀,要么寫,這樣復雜度就更低了。
比如我們創建一個文件流:
FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
這里面有幾個參數,分別是: 地址,FileMode,FileAccess,FileShare
那么看下FileMode 里面有什么吧。
public enum FileMode
{
CreateNew = 1,
Create = 2,
Open = 3,
OpenOrCreate = 4,
Truncate = 5,
Append = 6,
}
可以直接參考這個文檔:
https://learn.microsoft.com/zh-cn/dotnet/api/system.io.filemode?view=net-7.0
文檔中描述的比較清楚,就不贅述了。
FileAccess 第二個參數是FileAccess
[Flags]
public enum FileAccess
{
Read = 1,
Write = 2,
ReadWrite = Write | Read, // 0x00000003
}
權限,是讀,寫,或者讀和寫。
第4個參數是FileShare:
https://learn.microsoft.com/zh-cn/dotnet/api/system.io.fileshare?view=net-7.0
就是一些共享狀態,比如我這個文件在讀了,另外的文件是否可以讀。
這個可以根據自己的應用需求去處理。
然后我們一般情況下是會使用一個叫做File.create 方式去創建文件流的。
那么它的默認狀態是:
public static FileStream Create(string path, int bufferSize)
=> new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize);
所以這里要知道的是,如果我們使用File.create得到的FileStream。
如果文件存在呢,那么文件就會從頭開始寫,這點是新手值得注意的地方。
知道了前面這些基礎概念后,那么就可以往下走了。
文件
我們在應用層面向對象變成,那么我們要做的是什么?
要做的就是如果將這個文件,如果抽象成一個對象。
那么我們編程使用什么方式可以抽象成一個對象呢?
static void Main(string[] args)
{
FileInfo a = new FileInfo("a.txt");
Console.ReadKey();
}
有一個FileInfo 供我們使用,這樣就可以將文件映射成一個對象了。
一個FileInfo 我們可以拿到上面這些信息。
還可以對文件進行操作:
比如:
這些是操作文件的,那么有個問題啊,那就是如何操作目錄呢?
DirectoryInfo a = new DirectoryInfo("c://a");
目錄有目錄的信息。
這里值得注意的地方是,有些變成編程語言的思想是把目錄看出文件,然后再文件對象中就可以創建出目錄。
我們寫代碼的時候了解一下編程語言的思維就好了。
io 流的分類
從操作數據單位不同分為:
-
字節流
-
字符流
字節流-它包括流,FileStream,MemoryStream 和 BufferedStream。
字符流-它包括TextReader-TextWriter,StreamReader,StreamWriter和其他流。
通過流的流向不同分為:
-
輸入流
-
輸出流
通過流的角色的不同分為:
-
節點流
-
處理流/包裝流
這個下面都會介紹到。
字符流
簡單介紹一下字符流,這里面有一個問題。
我們都知道,在文件存儲的最小單位是字節。
總沒有聽說,一個文件存一個bit吧。字節是存儲的最小單位。
那么就有一個問題啊,比如我們io,那么最小有效單位應該也是字節吧。
傳輸的也是字節對吧,建立在這個理論基礎上,那么我們的字節流是合情合理的。
這個是傳輸層面的意義了。
那么為什么有字符流呢?因為我們發現字符格式有utf-8,ASCII等。
比如說utf-8,漢字是3個字節。比如一個我,那么應該讀取3個字節,而不是一個字節才是有意義的對吧。
那么就有字符流了。字節流是每次都是讀取一個字節,字符流每次讀取的那么就可能是一個字節或者兩個或者3個,看編碼形式。
static void Main(string[] args)
{
TextReader textReader = new StreamReader("a.txt", Encoding.ASCII);
Console.ReadKey();
}
StreamReader 是文件字符流。TextReader 是其基類。
所有的字符流的讀取基類是TextReader。
StreamReader 是對文件的字符流的讀寫,那么StringReader 是對內存的讀寫了。
其他的就不演示了,自我熟悉就好,c# 官方文檔更加專業。
看文檔就好:
https://learn.microsoft.com/zh-cn/dotnet/api/system.io.stringreader?view=net-7.0
節點流和處理流
什么是節點流呢:
節點流是從一個特定的數據源讀寫數據,如:StreamReader、FileStream。
就是直接從一個數據源進行讀寫。
那么什么是處理流呢?
處理流也叫做包裝流,是連接在存在的流之上,為程序提供更為強大的讀寫功能,如BufferedStream。
static void Main(string[] args)
{
var a= File.Create("a.txt");
BufferedStream stream = new BufferedStream(a);
Console.ReadKey();
}
二進制處理流
二進制處理流是這樣的,其實很像字符流。
比如說,我們除了存字符,我們還可以存數字對吧。
還可以存bool類型。
那么其實就是如果是讀取int,那么就是讀取4個字節,讀取bool 就是讀取兩個字節。
static void Main(string[] args)
{
MemoryStream aStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(aStream);
writer.Write(10);
writer.Write(20);
Console.Read();
}
讀取的時候也是一樣的。
結
也沒什么好記的,主要是整理一些概念,一些實現原理,會查文檔就好。