• 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[] 的对应的数据(图片)是完整数据后,才可解析,当前如果是这种复杂的处理,前提是各部分对应的长度是已知,根据这些长度截取对应的索引部分,对号入座去执行解析,这样才更稳妥。

  • 相关阅读:
    servlet的之前与之后的基本使用
    java HashMap插入重复Key值问题
    ConcurrentHashMap底层实现原理(JDK1.7 & 1.8)
    spring cloud实现热加载
    spring cloud各个组件以及概念的解释和基本使用
    深入理解java 虚拟机 jvm高级特性与最佳实践目录
    【leetcode】1、两数之和
    【Java 基础领域】二维数组创建内存图
    【Java EE领域】com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'salary' in 'fi
    【JavaEE领域】com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'mp.employee' doesn't exi
  • 原文地址:https://www.cnblogs.com/Sientuo/p/9316498.html
Copyright © 2020-2023  润新知