重學c#系列—— IO流[三十四]

敖毛毛發表於2023-02-04

前言

簡單介紹一下io流。

以前寫過兩篇,裡面是java 語言寫的,簡單介紹了一下io流,這裡是對io流的整理。

https://www.cnblogs.com/aoximin/p/12007925.html

https://www.cnblogs.com/aoximin/p/12044270.html

這裡說一下一個經驗,僅獻給入門的人。

剛寫程式碼進行io流讀取或者寫入的時候,有一個思維去考慮這個io流是怎麼從磁碟讀取的或者怎麼從記憶體讀取的,

這個想法是沒錯的,但是不是應用層面考慮的東西,是作業系統和硬體的結合(作業系統篇會介紹全面),這會使人腦複雜,下面請以應用層面考慮問題。

正文

在io流中有幾個概念必須知道:

  1. 字元流

  2. 位元組流

  3. 節點流

  4. 處理流

如果不清楚這些概念,那麼你就需要看完這一篇回憶一下以前的基礎。

在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 流的分類

從運算元據單位不同分為:

  1. 位元組流

  2. 字元流

位元組流-它包括流,FileStream,MemoryStream 和 BufferedStream。

字元流-它包括TextReader-TextWriter,StreamReader,StreamWriter和其他流。

透過流的流向不同分為:

  1. 輸入流

  2. 輸出流

透過流的角色的不同分為:

  1. 節點流

  2. 處理流/包裝流

這個下面都會介紹到。

字元流

簡單介紹一下字元流,這裡面有一個問題。

我們都知道,在檔案儲存的最小單位是位元組。

總沒有聽說,一個檔案存一個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();
}

讀取的時候也是一樣的。

也沒什麼好記的,主要是整理一些概念,一些實現原理,會查文件就好。

相關文章