u盤打開時提示io錯誤(U盤io錯誤)0.前言在之前的章節中,大致介紹了C#中的一些基本概念。這篇我們將介紹一下C#的I/O操作,這將也是一個小連續劇。這是第一集,我們先來簡單了解一下C#中的I/O框架。1.什么是I/OI/O的全稱是input/output,翻譯過來就是輸入/輸出。對于一個系統或者計算機來說,鍵盤、U盤、網絡接口、顯示器、音響、攝像頭等都是IO設備。那么,對于一個程序I/O又是什么呢?對于程序而言,I/O就是與外界進行數據交換的方式。借用一句廣告詞,程序不生產數據,只是數據的搬用工。當然,正如XX還需要對水進行過濾、消毒等工序一樣,程序也要對數據進行運算,所以也不完全算是搬用工,嚴格來講是加工廠。那么,I/O就是工廠的原料提供商和成品銷售商。在C#中,I/O體系整體分為三個部分,后臺存儲流、裝飾器流、流適配器,具體劃分:在流與流之間,都是采用字節數據進行交換,所以可以得到一個簡單的結論,I/電腦O在程序中表現為字節流,換句話說I/O就是將各種數據轉成字節的工具。3.Stream基類C#中,所有流都是繼承自Stream類,Stream類定義了流應該具有的行為和屬性,使得開發人員可以忽略底層的操作系統和基礎設備的具體細節。C#對流的處理忽略了讀流和寫流的區別,使其更像是一個管道,方便數據通信。流涉及到三個基本操作:讀取-將數據從流中傳輸到數據結構中寫入-將數據從數據源寫入流中查找-對流中操作的當前位置進行查找和修改因為流的特性,可能并不是所有的流都支持這三種操作,所以Stream提供了三個屬性,以方便確認流是否支持這三種操作:publicabstractboolCanRead{get;}//獲取指示當前流是否支持讀取的值publicabstractboolCanWrite{get;}//獲取指示當前流是否支持寫入功能的值publicabstractboolCanSeek{get;}//獲取指示當前流是否支持查找功能的值以上這三個屬性均由子類根據自身特性確認是否支持讀取、寫入、查找,可能三個屬性不會都為true,但絕對不會都為false。下面是一些常見的流:FileStream用來操作文件的流MemoryStream操作內存的流BufferedStream緩存流,用來增強其他流的操作性能NetworkStream使用網絡套接字進行操作的流Pipestream通過匿名和命名管道進行讀取和寫入CryptoStream用于將數據流鏈接到加密轉換電腦4.操作C#中I/O的操作都屬于System.IO這個命名空間,在這個命名空間中C#定義了文件相關的類、各種流、裝飾器流、適配器以及其他一些相關的結構體。在以System.IO開頭的命名空間中,C#對IO進一步擴展,并提供了流壓縮和解壓縮(System.IO.Compression),搜索和枚舉文件系統元素(System.IO.Enumeration),提供用于使用內存映射文件的類(System.IO.MemoryMappedFiles)等內容。我們先略過之后篇幅會介紹的內容不提,先來看一下Stream類里重要的屬性和方法:1.流里數據的長度publicabstractlongLength{get;}當Stream對象的CanSeek為true時,也就是流支持搜索的時候,可以通過這個屬性確認流的長度,也就是有多少個字節的數據。2.流的位置publicabstractlongPosition{get;set;}同長度的前提條件一致,當Stream對象支持搜索的時候,可以通過該屬性確認流的位置或者修改流的位置。3.讀取流里的數據publicabstractintRead(byte[]buffer,intoffset,intcount);publicvirtualintReadByte();這是兩種不同的讀取方式,第一種是每次讀取多個字節的數據,第二個電腦是每次只讀一個字節的數據。這里來細細講解一下區別:publicabstractintRead(byte[]buffer,intcount);表示流每次最多讀取count個字節的數據,然后將數據放到buffer中,位置從下標為offset開始,并返回實際讀取的字節數,如果流已經讀完了,則返回0。這個過程中,Position會后移實際讀取長度,如果流支持搜索,程序中可以調用這個屬性。所以這里就有會這樣的一個限制:offset+count<=buffer.Length,換句話說,偏移量+最大讀取數目不能大于緩存數組的長度。因為這個方法返回一個實際讀取長度,可能有人會這樣判斷是否讀完:根據返回的結果與count比,如果返回的長度小于count則認為流已經讀完;否則流還沒讀完。有一些流可能會達成這樣的效果,但是很多流并不能以此為依據來判斷流是否讀完,也許某一次讀取長度小于count,然后再讀一次發現又有數據了。這是因為IO在系統中屬于高耗時操作,大部分情況下IO的性能和程序的運算速度相差甚遠。所以經常會出現這樣的情景:流的長度是100,給了長度為100的緩存字節數組,然后第一次讀取了10個字節,第二次讀取了5個字節,這樣一點一點的把這100個字節讀取到。所以,必須以返回值為0作為流的讀完判斷依據。publicvirtualintReadByte();這個方法很簡單,每次從流里讀取一個字節的數據,如果讀取完成返回-1。可能有人會疑惑了,這個方法明明是讀取一個字節,也就是個byte,那為什么返回類型是int呢?很簡單,因為byte沒有負數,而int有。所以,當返回值不等于-1的時候,可以放心的類型轉換為byte。4.把數據寫入流publicabstractvoidWrite(byte[]buffer,intcount);publicvirtualvoidWriteByte(bytevalue);流的寫入與讀取相比就簡單多了,至少我們不用判斷流的位置?,F在簡單分析一下:publicabstractvoidWrite(byte[]buffer,intcount);表示從buffer的offset下標開始,取count個字節寫入流里。所以,對offset、count的限制依舊,和不能大于數組的長度。寫入成功,流的位置會移動,否則將保持現有位置。publicvirtualvoidWriteByte(bytevalue);這個方法就更簡單了,直接寫一個字節給流。5.關閉或銷毀流流在操作完成之后,需要將其關閉以釋放流所持有的文件或IO設備等資源。很多人在使用電腦的時候,不能用QQ發送在本地已經打開的excel文件,它會提示文件被占用無法傳輸。這就是因為Excel打開了這個文件,就持有一個文件相關的流,所以QQ無法發送。解決辦法很簡單,關掉excel軟件即可。回到當前,也就是我們在使用完成之后必須關閉流。那么我們該如何關閉流呢?調用以下方法:publicvirtualvoidClose();C#雖然設置了Close方法,但是并不支持開發者在編寫程序的時候手動調用Close方法,更推薦使用:publicvoiddispose();這個方法會將釋放流所持有使用的資源,并關閉流。當前需要注意的一個地方是,在把流關閉或釋放之前把流里的數據推送到基礎設備,即調用:publicabstractvoidFlush();有一些流設置了自動推送功能,如果遇到這種流則不需要手動調用該方法。對于流來說,一旦銷毀或關閉,這個流就無法二次使用了,所以調用了Close、dispose之后再次嘗試讀取/寫入流都會報錯5.本篇總結以及下篇預告本篇內容大概介紹了一下C#的IO體系以及一些基本操作,下一篇將介紹如何操作文件。更多內容煩請關注我的博客《高先生小屋》電腦