byte[] 解析、轉碼二三事


 

1.先從byte 說起, byte 范圍為 0~255 的整數,這個區間是在 int 范圍中,所以 當byte 轉為 int 時,則為小范圍轉大范圍,隱式轉換可以直接轉換,反過來就是顯式轉換 需要Convert 下

            byte a = 1;
            byte b = 2;
            //正整數+正整數 可以賦值給byte(正常理解應該是,整型轉為byte型,特例
            byte c = 1 + 2;
            // byte類型+整數 為 int類型
            byte d = Convert.ToByte(a + 1);
            // byte類型 + byte類型 為 int類型         
            byte e = Convert.ToByte(a + b);

                   

            //將int32轉換為字節數組,防止數據丟失,如右圖

            byte[] bytes = BitConverter.GetBytes(258);

            //此外Byte[] 與 String 轉換          

          byte[] bts = System.Text.Encoding.Default.GetBytes(str);
          string str = System.Text.Encoding.Default.GetString(bts);
                  

2.對於bytes數組來說,其實也沒啥太大的差別,記住一些常用的操作即可,比如,合並,截取,拼接

            byte[] bts1 = new byte[9];
            bts1[0] = 10;
            bts1[1] = 12;

            byte[] bts2 = new byte[6];
            bts2[0] = 14;
            bts2[1] = 15;
            bts2[2] = 16;

            //累加,值為 10,12,0,0,0,0,0,0,0,14,15,16,0,0,0
            bts1 = bts1.Concat(bts2).ToArray();  

            //當一個byte[] 數組特別大的時候,想截取其中的有效值(比如長度1000,從600以后都是空值0)
            bts1 = bts1.Skip(0).Take(600).ToArray();

            //截取有效值后拼接
            bts1 = bts1.Skip(0).Take(300).ToArray().Concat(bts2.Skip(0).Take(100).ToArray()).ToArray();

3. 實際項目中往往涉及到一些繁復的轉換,諸如,byte[]、image、bitmap 、16進制之間的相互轉換

        #region  圖片格式轉byte[]

        public byte[] ImageToBytes(Image image)
        {
            ImageFormat format = image.RawFormat;
            using (MemoryStream ms = new MemoryStream())
            {
                //直接轉會出現問題,中間用Bitmap包裹一層
                Bitmap t = new Bitmap(image);
                t.Save(ms, format);
                return ms.ToArray();
            }
        }
        #endregion


        #region byte[] 轉圖片
        public Image convertImg(byte[] datas)
        {
            MemoryStream ms = new MemoryStream(datas);
            Image img = Image.FromStream(ms, true);  
            //流用完要及時關閉  
            ms.Close();
            return img;
        }     
        #endregion

        #region bitmap 轉byte數組
        public static byte[] BitmapToBytes(Bitmap Bitmap)
        {

           MemoryStream mstream = new MemoryStream();
           Bitmap.Save(mstream, System.Drawing.Imaging.ImageFormat.Bmp);
           byte[] byData = new Byte[mstream.Length];
           mstream.Position = 0;
           mstream.Read(byData, 0, byData.Length); mstream.Close();
           return byData;
        }

 

解析字符串時,比較簡單,但是需要注意的是,如果是單純的byte數組沒問題,如果byte[] 中含有字符串,圖片等,直接解析肯定是亂碼,一定要先根據長度截取想對應部分后分別再去解析

            //將byte數組 轉換為string,中文字符時使用 UTF-8
            string middataLen = Encoding.Default.GetString(bt1s, 0, bts1.Length);
            //參數為byte[] bytes, int index, int count) 三個參數為解析指定長度的數組,只有bytes一個參數時為解析全部
            string middataLen1 = Encoding.Default.GetString(bt1s);

現有一復雜字節數組,其中含有string、圖片, 如果需將此字節數組存入本地txt文件中,常規方式肯定會出現亂碼,實際上往往是先將數組轉換為16進制,然后在寫入到流文件中,需要的時候再去解析該文件,轉成byte[] 數組再進行操作

        #region byte[]數組轉16進制文件

        private static void WriteToTxt(byte[] bytContents,string strpath)
        {
            int length = bytContents.Length;
            StringBuilder builder = new StringBuilder(length * 3);
            foreach (byte value in bytContents)
            {
                builder.AppendFormat("{0:X} ", value);
            }
            System.IO.StreamWriter sw = new System.IO.StreamWriter(strpath, false, System.Text.Encoding.Default);
            sw.Write(builder.ToString());
            sw.Close();
        }

        #endregion
      
        #region (16進制)文件 轉byte[]   
        /// <summary>
        /// </summary>
        /// <param name="strFile">文件路徑</param>
        /// <returns></returns>
        public static byte[] Read(string strFile)
        {
            StreamReader sr = new StreamReader(strFile, Encoding.Default);
            string strContent = sr.ReadToEnd();
            sr.Close();
            string[] arry = strContent.Split(' ');
            arry = arry.Skip(0).Take(arry.Length - 1).ToArray();
            List<byte> lstRet = new List<byte>();
            foreach (string s in arry)
            {
                lstRet.Add(Convert.ToByte(s, 16));
            }
            return lstRet.ToArray();
        }
        #endregion

以上是關於byte[] 的基本操作,基本滿足常規要求,下面來說說TCP/IP接口,調用此接口,接收數據,然后解析。

        //創建連接參數對象
private IPAddress serverIP = IPAddress.Parse("127.0.00.1"); private IPEndPoint serverFullAddr; private Socket sock; private void btn_conn_Click(object sender, EventArgs e) { btn_conn.Enabled = false; serverIP = IPAddress.Parse(tbxIP.Text); try { serverFullAddr = new IPEndPoint(serverIP, int.Parse(tbxPort.Text));//設置IP,端口 sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //指定本地主機地址和端口號 sock.Connect(serverFullAddr);
//發送數據
//sock.Send(bytes);
//接收數據 byte[] conn_bts = new byte[500]; int conn_Len = sock.Receive(conn_bts); var conn_mess = Encoding.Default.GetString(conn_bts, 0, conn_Len); //判斷是否連接成功 //if(conn_mess)
//
// sock.Close(); } catch (Exception ee) { btn_conn.Enabled = true; lab_err.Text = "連接服務器失敗。。。請仔細檢查服務器是否開啟" + ee.Message; } } //關閉連接 private void btn_close_Click(object sender, EventArgs e) { lab_err.Text = ""; sock.Close(); btn_conn.Enabled = true; btn_Send.Enabled = false; }

 調用TCP/IP 接口的時候,使用Sock的Receive() 方法去接接收Stream流數據時,如果一次未接收完,第二次接收是從上次結束時的末尾開始接收

             byte[] bytes1 = new byte[500];
             
            //byte[]數組一旦定義長度,如果接口總數據長度小於500,則bytes1中有效長度為Row,剩下的索引值為0
             int row = sock.Receive(bytes1);  //等價於  sock.Receive(bytes1, 500, 0);
          
            //當接口返回數據總長度大於500的時候,比如為800,再次使用Receive(),是從索引為500的位置開始接收
            //如果想把余下800-500=300 一次性接收完,則為
            byte[] bytes2 = new byte[800-row];
            int count = sock.Receive(bytes2);
           
            //有時候數據很長,一次或者兩次無法接受完,這時需要寫一個循環接收,兩種思路
            //①返回值長度累加==接口數據總長度。適用於復雜的字節,同時包含數字,漢字,圖片等
            //②寫一個循環 do while , 根據返回值長度是否為0來判斷,適用於簡單的字節
            
        

對於第二種中情況,一邊接收一邊解析,然后累加解析結果,如果是第一種情況,就不能這樣處理,必須保證 byte[] 的對應的數據(圖片)是完整數據后,才可解析,當前如果是這種復雜的處理,前提是各部分對應的長度是已知,根據這些長度截取對應的索引部分,對號入座去執行解析,這樣才更穩妥。

 


免責聲明!

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



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