C#流之——MemoryStream ,常用方法用法測試


流的inputStream和OUtputStream和Read和Writer總是搞混,原來是我沒理清流程,流的產生到消失過程:

數據 —> 通過inputStream()、Read()轉化為流 —> 通過outputStream()、Writer()轉化為數據,就像流是通過一個小細管道傳輸的,input輸入管道變為流,output輸出管道變為數據,流類讀取數據為流,流將流寫入數據。

C# 中的流

抽象基類 Stream 支持讀取和寫入字節。 所有表示流的類都繼承自 Stream 類。 Stream 類及其派生類提供數據源和存儲庫的常見視圖,使程序員不必了解操作系統和基礎設備的具體細節。

流涉及三個基本操作:

讀取 - 將數據從流傳輸到數據結構(如字節數組)中。

寫入 - 將數據從數據源傳輸到流。

查找 - 對流中的當前位置進行查詢和修改。

根據基礎數據源或存儲庫,流可能只支持這些功能中的一部分。 例如,PipeStream 類不支持查找。 流的 CanRead、CanWrite 和 CanSeek 屬性指定流支持的操作。

下面是一些常用的流類:

  • FileStream - 用於對文件進行讀取和寫入操作。
  • IsolatedStorageFileStream - 用於對獨立存儲中的文件進行讀取或寫入操作。
  • MemoryStream - 用於作為后備存儲對內存進行讀取和寫入操作。
  • BufferedStream - 用於改進讀取和寫入操作的性能。
  • NetworkStream - 用於通過網絡套接字進行讀取和寫入。
  • PipeStream - 用於通過匿名和命名管道進行讀取和寫入。
  • CryptoStream - 用於將數據流鏈接到加密轉換。

這里主要介紹后備存儲為內存的流:MemoryStream 

主要介紹方法:

yier[index]).ToString("X2");//byte轉化為兩個16進制的數。X為16進制,2為 每次都是兩位數,即10轉化為0x0A而不是0xA。
注意:16進制的數和16位整數是不一樣的,16進制數字占4位,半個字節,即一個字節轉化為2個16進制的數,16位整數是short類型的數對應兩個字節。

public override void Write(byte[] buffer, int offset, int count);//byte[]寫入流,然后流中就有Length和Position了。

public override void WriteByte(byte value); //逐字節將緩存區寫入流,流的Length逐字節增加,和position逐漸增加。

public override long Seek(long offset, SeekOrigin loc); //設置position位置,

public override int Read(byte[] buffer, int offset, int count);//讀取流中數據到緩沖區,offset+count不能超過緩沖數組的Length

public override int ReadByte();//ReadByte從當前流讀取一個字節,返回將字節轉換為Int32,或者-1(如果已經到達流的末端)。ToByte將int轉化為字節

public virtual byte[] GetBuffer();//獲取創建該流的字節數組,后邊流數據改變了,此數組也會改變。因為此不是基本類型也不是string不可變類型。

//將漢字轉化為流,和將流解析為漢字,編碼規則要對應一致,否則解析出來亂碼。

byte[] secondString2 = Encoding.UTF8.GetBytes("上山打老虎66");

Console.WriteLine(Encoding.UTF8.GetString(secondString2));//上山打老虎66,加密和解碼編碼字符集要一致。

Array.Copy(secondString, 0, testArrayCopy, 3, 14);//從源數組的0位置開始復制,復制到目標數組從0位置開始,復制14個元素。目標數組長度必須大於17。

ushort opcode = BitConverter.ToUInt16(memoryStream.GetBuffer(), Packet.OpcodeIndex); //從startIndex位置開始解析之后的兩個字節 為16位無符號整數。,即返回轉化了的opcode。opcode(ushort)兩個字節,開始於下標1。

public static void Main()
        {
            byte[] array = new byte[1];   //定義一組數組array
            array = System.Text.Encoding.ASCII.GetBytes("dc"); //string轉換的字母對應的ASCALL碼
            string d = Encoding.UTF8.GetString(array); //dc
            array = System.Text.Encoding.UTF8.GetBytes("一二"); //string轉換的字母對應的六個byte數組。三個字節一個漢字。
            string d2 = Encoding.UTF8.GetString(array); //一二
            array = System.Text.Encoding.Unicode.GetBytes("撒呢過"); //string轉換的漢字對應的6個byte數組。兩個字節一個漢字
            string d3 = Encoding.Unicode.GetString(array); //撒呢過

            UnicodeEncoding uniEncoding = new UnicodeEncoding();
            byte[] yier = uniEncoding.GetBytes("一二");
            //字節byte[]轉化為16進制。
            StringBuilder strBuider = new StringBuilder();
            for (int index = 0; index < yier.Length; index++)
            {
                strBuider.Append(((int)yier[index]).ToString("X2"));//
            }
            Console.WriteLine("一二的字節碼轉化為16進制:"+ strBuider.ToString());///結果:004E8C4E,而一二的Unicode編碼是:\u4E00\u4E8C,即每16位表示一個漢字,
            ///但是在將 UNICODE字符編碼的內容轉換為漢字的時候,字符是從后面向前處理的,所以要得到漢字需要將前8位和后8位字符調換組合和“\u”得到漢字的編碼。


            int count;
            byte[] byteArray;
            char[] charArray;
            // Create the data to write to the stream.
            byte[] firstString = uniEncoding.GetBytes("一二三四五");
            byte[] secondString = uniEncoding.GetBytes("上山打老虎66");
            using (MemoryStream memStream = new MemoryStream(100))
            {
                byte[] getBuff = memStream.GetBuffer(); //獲取創建該流的字節數組,后邊流數據改變了,此數組也會改變。因為此不是基本類型也不是string不可變類型。
                // Write the first string to the stream.
                memStream.Write(firstString, 0, firstString.Length);//byte[]寫入流,然后流中就有Length和Position了。
                //byte[] getBuff2 = memStream.GetBuffer();
                //MemoryStream memStream2 = new MemoryStream();
                //MemoryStream memStream3 = new MemoryStream(secondString);
                //byte[] getBuff3 = memStream2.GetBuffer();//{byte[0]}
                //byte[] getBuff4 = memStream3.GetBuffer();//未經授權的訪問異常:內存流的內部緩沖區不能被訪問異常。


                // Write the second string to the stream, byte by byte.
                count = 0;
                while (count < secondString.Length)
                {
                    memStream.WriteByte(secondString[count++]);//逐字節將將緩存區寫入流,流的Length逐字節增加,和position逐漸增加。
                }

                // Write the stream properties to the console.
                Console.WriteLine("Capacity={0},Length={1},Position={2}\n", memStream.Capacity.ToString(), memStream.Length.ToString(), memStream.Position.ToString());

                // Set the position to the beginning of the stream.
                memStream.Seek(0, SeekOrigin.Begin);//設置position=0
                //memStream.Seek(5, SeekOrigin.Current);//設置position=0
                //memStream.Seek(3, SeekOrigin.Begin);//設置position=3
                //memStream.Seek(3, SeekOrigin.Current);//設置position=6 = 3+3

                // Read the first 20 bytes from the stream.
                byteArray = new byte[memStream.Length];
                count = memStream.Read(byteArray, 0, 20);//offset+count不能超過數組的Length
                //count = memStream.Read(byteArray, 0, 10);//讀取流中數據到byteArray緩沖區。則從流的當前位置開始讀取,一直讀到流結束或count個字節。

                // Read the remaining bytes, byte by byte.
                while (count < memStream.Length)//即當未讀完流時
                {
                    //ReadByte從當前流讀取一個字節,返回將字節轉換為Int32,或者-1(如果已經到達流的末端)。ToByte將int轉化為字節
                    byteArray[count++] = Convert.ToByte(memStream.ReadByte());
                }

                Console.WriteLine(Encoding.Unicode.GetString(byteArray));//一二三四五上山打老虎66
                Console.WriteLine(Encoding.UTF8.GetString(byteArray));//亂碼
                byte[] secondString2 = Encoding.UTF8.GetBytes("上山打老虎66");
                Console.WriteLine(Encoding.UTF8.GetString(secondString2));//上山打老虎66,加密和解碼編碼字符集要一致。

                byte[] testArrayCopy = new byte[20];
                Array.Copy(secondString, 0, testArrayCopy, 3, 14);//從源數組的0位置開始復制,復制到目標數組從0位置開始,復制14個元素。目標數組長度必須大於17。
                
                charArray = new char[uniEncoding.GetCharCount(testArrayCopy, 3, 14)];
                uniEncoding.GetDecoder().GetChars(testArrayCopy, 3, 14, charArray, 0);//decoder解碼器,可解析byte[]數組中一部分元素,
                Console.WriteLine(Encoding.Unicode.GetString(byteArray)); //上山打老虎66
            }
        }

 ET框架中:將信息轉化為流,和將流解析成所需內容

SerializeTo
((Google.Protobuf.IMessage) message).WriteTo(stream);或
MongoPacker.SerializeTo(object obj, MemoryStream stream)
DeserializeFrom
MemoryStream stream = session.Stream;
            ///第一個參數:流中新位置,相對於第二個參數,第一個參數可正可負
            stream.Seek(Packet.MessageIndex, SeekOrigin.Begin);//當前流位置設置為指定的值。
            stream.SetLength(Packet.MessageIndex);
            byte[] b = stream.GetBuffer();
            session.Network.MessagePacker.SerializeTo(new C2G_LoginGate() { Key = 1, RpcId = 1 }, stream);//對象序列化為流
            stream.Seek(Packet.MessageIndex, SeekOrigin.Begin);//當前流位置設置為指定的值。從對應實例開始的流位置開始 才能正確解析。
            object message = session.Network.MessagePacker.DeserializeFrom(Activator.CreateInstance(typeof(C2G_LoginGate)), stream);//對象序列化為流

 Packet類

    public static class Packet
    {
        public const int PacketSizeLength2 = 2;//引用的地方,傳遞的是可選參數 默認是2
        public const int PacketSizeLength4 = 4;//NetInnerComponent組件Awake傳遞是4,外網是默認的2。
        public const int FlagIndex = 0;
        public const int OpcodeIndex = 1;//Opcode下標開始位置,因為0位置存的是flag,
        public const int MessageIndex = 3;//消息內容下標開始位置,因為0位置flag,1、2位置Opcode。opcode是short類型對應兩個字節
    }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM