android 数据解析总结(各种解析)

来源:互联网 发布:网络词语大全及意思 编辑:程序博客网 时间:2024/05/21 09:17

从事android开发以来,解析过不少数据,都是根据所谓的协议来的。其实,这些协议都是双方约定或者一方约定的数据格式。

1,标准的gga坐标数据解析

例如:$GPGGA,033744,2446.5241,N,12100.1536,E,1,10,0.8,133.4,M,,,,*1F

看看geomap源码是怎么对坐标数据的解析的 NMEA 0183

/* * OpenNMEA - A Java library for parsing NMEA 0183 data sentences * Copyright (C)2006 Joey Gannon *  * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. *  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA */package com.opennmea;/** * An object for storing and comparing geographic latitude and longitude *  * @author Joey Gannon * @version 1.00, 08/11/06 * @since OpenNMEA v0.1 */public class Geocoordinate implements Comparable<Geocoordinate>{private int latdeg,londeg,latmin,lonmin;private double latsec,lonsec,lattot,lontot;private char mode;private boolean valid=true;/** * Constructs a Geocoordinate from latitude and longitude strings, with cardinal direction * indicated by separate strings * <p> * This constructor defaults to the decimal minutes output mode. * <p> * If the strings passed to this constructor are malformed, the values will default to * <code>{0.0, 0.0}</code>.  * @param lat Latitude, in the form DDmm[.mmmm] * @param ns North/South ("N" or "S") * @param lon Longitude, in the form DDDmm[.mmmm] * @param ew East/West ("E" or "W") */public Geocoordinate(String lat,String ns,String lon,String ew){this(lat.equals("")?0.0:(Integer.parseInt(lat.substring(0,2))+Double.parseDouble(lat.substring(2))/60)*(ns.equals("N")?1:-1),lon.equals("")?0.0:(Integer.parseInt(lon.substring(0,3))+Double.parseDouble(lon.substring(3))/60)*(ew.equals("E")?1:-1));if((lat.equals(""))||(lon.equals("")))valid=false;mode='M';}/** * Constructs a Geocoordinate from floating-point latitude and longitude values, with * cardinal direction indicated by numerical sign * <p> * This constructor defaults to the decimal degrees output mode. * @param lat Latitude, in decimal degrees (south is negative) * @param lon Longitude, in decimal degrees (west is negative) */public Geocoordinate(double lat,double lon){while(lat<-90)lat+=180;while(lat>90)lat-=180;while(lon<=-180)lat+=360;while(lon>180)lat-=360;lattot=lat;lontot=lon;latdeg=(int)lat;londeg=(int)lon;latmin=(int)(60*(lat-latdeg));lonmin=(int)(60*(lon-londeg));latsec=60*(60*(lat-latdeg)-latmin);lonsec=60*(60*(lon-londeg)-lonmin);mode='D';}/** * Sets the output mode to decimal degrees */public void toDegrees(){mode='D';}/** * Sets the output mode to degrees and decimal minutes */public void toMinutes(){mode='M';}/** * Sets the output mode to degrees, minutes, and decimal seconds */public void toSeconds(){mode='S';}/** * Tells where the current mode applies the fractional part of the latitude * and longitude values * <p> * Possible modes are degrees (<code>'D'</code>), minutes (<code>'M'</code>), * or seconds (<code>'S'</code>). * @return the current mode */public char getMode(){return mode;}/** * Returns the latitude, formatted according to the current mode * <p> * If the latitude stored by this Geocoordinate was 12.3456, then * the array returned for each mode would be:<br> * Degrees mode: <code>[12.3456]</code><br> * Minutes mode: <code>[12.0, 20.736]</code><br> * Seconds mode: <code>[12.0, 20.0, 44.16]</code> * @return the latitude * @see Geocoordinate#getLatitudeDegrees() */public double[] getLatitude(){double[] array;if(mode=='D'){array=new double[1];array[0]=lattot;}else if(mode=='M'){array=new double[2];array[0]=(double)latdeg;array[1]=latmin+latsec/60;}else{array=new double[3];array[0]=(double)latdeg;array[1]=(double)latmin;array[2]=latsec;}return array;}/** * Returns the latitude in decimal degrees * <p> * This is equivalent to <code>getLatitude()[0]</code> in Degrees mode. * @return the latitude * @see Geocoordinate#getLatitude() */public double getLatitudeDegrees(){return lattot; }/** * Returns the longitude, formatted according to the current mode * <p> * If the longitude stored by this Geocoordinate was 12.3456, then * the array returned for each mode would be:<br> * Degrees mode: <code>[12.3456]</code><br> * Minutes mode: <code>[12.0, 20.736]</code><br> * Seconds mode: <code>[12.0, 20.0, 44.16]</code> * @return the longitude * @see Geocoordinate#getLongitudeDegrees() */public double[] getLongitude(){double[] array;if(mode=='D'){array=new double[1];array[0]=lontot;}else if(mode=='M'){array=new double[2];array[0]=(double)londeg;array[1]=lonmin+lonsec/60;}else{array=new double[3];array[0]=(double)londeg;array[1]=(double)lonmin;array[2]=lonsec;}return array;}/** * Returns the longitude in decimal degrees * <p> * This is equivalent to <code>getLongitude()[0]</code> in Degrees mode. * @return the longitude * @see Geocoordinate#getLongitude() */public double getLongitudeDegrees(){return lontot;}/** * Determines if a coordinate is valid * <p> * An invalid coordinate could be generated by the constructor if * passed invalid strings. This method is helpful in filtering out * such coordinates. * @return true if the coordinate is valid, false otherwise */public boolean isValid(){return valid;}/** * Returns the distance between two Geocoordinates on Earth, in meters * <p> * In order to fulfill the contract of <code>Comparable</code>, this method returns * a negative distance if <code>this</code> is farther south than <code>g</code>. If * <code>this</code> and <code>g</code> are at the same latitude, then this method * returns a negative distance if <code>this</code> is farther west than <code>g</code>. * @return the distance between two Geocoordinates * @see java.lang.Comparable#compareTo(java.lang.Object) */public int compareTo(Geocoordinate g){return (int)(Math.toDegrees(Math.acos(Math.sin(Math.toRadians(lattot))*Math.sin(Math.toRadians(g.getLatitudeDegrees()))+Math.cos(Math.toRadians(lattot))*Math.cos(Math.toRadians(g.getLatitudeDegrees()))*Math.cos(Math.toRadians(lontot-g.getLongitudeDegrees()))))*111189.577)*(lattot==g.getLatitudeDegrees()?(lontot>g.getLongitudeDegrees()?1:-1):(lattot>g.getLatitudeDegrees()?1:-1));}/** * Determines if this Geocoordinate is equal to another object * <p> * A comparison only makes sense if the object being compared is also a Geocoordinate, * so this method returns false if the parameter is not an instance of Geocoordinate. * @return true if the objects are equal, false otherwise * @see java.lang.Object#equals(java.lang.Object) */@Overridepublic boolean equals(Object o){if(!(o instanceof Geocoordinate))return false;return ((lattot==((Geocoordinate)o).getLatitudeDegrees())&&(lontot==((Geocoordinate)o).getLongitudeDegrees()));}/** * Returns a string representation of the coordinate * @return a string representation of the coordinate * @see java.lang.Object#toString() */@Overridepublic String toString(){if(mode=='D')return (latdeg+latmin/60)+"бу"+' '+(londeg+lonmin/60)+"бу";else if(mode=='M')return latdeg+"бу"+Math.abs(latmin)+'\''+' '+londeg+"бу"+Math.abs(lonmin)+'\'';elsereturn latdeg+"бу"+Math.abs(latmin)+'\''+Math.abs(latsec)+'\"'+' '+londeg+"бу"+Math.abs(lonmin)+'\''+Math.abs(lonsec)+'\"';}}

其中经纬度都是有正负,以及南北半球,东西半球之分的

上面的代码主要就是

纬度解析:lat.equals("")?0.0:(Integer.parseInt(lat.substring(0,2))+Double.parseDouble(lat.substring(2))/60)*(ns.equals("N")?1:-1)

经度解析:lon.equals("")?0.0:(Integer.parseInt(lon.substring(0,3))+Double.parseDouble(lon.substring(3))/60)*(ew.equals("E")?1:-1)

关于其他的mnea 0183经纬度解析可参照:GPS NMEA-0183标准详解(常用的精度以及经纬度坐标)

2,数据解析

数据解析,收到的数据如下
数据分析,前面的006是没什么用的。Ed开始,后面跟着一个空格,或者是回车换行。
1.811后面也是回车换行。

006Ed 0010,0,0.000,0.0,-99998.446,-99998.102,1.811

解出来需要的数据如下:-99998.446
-99998.102
1.811

代码解析:

private void totalStationData(int nLength, byte[] data){try {String dyString1 = new String(data, 0, nLength);if (dyString1.contains("006\r\n")) {return;}strData = strData + dyString1;if (strData.contains("Ed" )&& strData.substring(strData.length()-2,strData.length()).contains("\r\n")&& strData.length()>15) {String[] srcData = strData.split("Ed");if (srcData[1] != null && srcData[1].length() >=20) {Log.i("Show", strData);String[] srcStrings =  srcData[1].split(",");if (srcStrings != null && srcStrings.length >= 5) {if (srcStrings[4].substring(0, 1).equals("-")) {mdTotalStationCoord[0] = -Double.valueOf(srcStrings[4].substring(1,srcStrings[4].length()));}else {mdTotalStationCoord[0] = Double.valueOf(srcStrings[4]);}Log.i("Show",String.valueOf(mdTotalStationCoord[0]));if (srcStrings[5].substring(0, 1).equals("-")) {mdTotalStationCoord[1] = -Double.valueOf(srcStrings[5].substring(1,srcStrings[5].length()));}else {mdTotalStationCoord[1] = Double.valueOf(srcStrings[5]);}Log.i("Show", String.valueOf(mdTotalStationCoord[1]));if (srcStrings[6].substring(0, 1).equals("-")) {mdTotalStationCoord[2] = -Double.valueOf(srcStrings[6].substring(1,6));}else {mdTotalStationCoord[2] = Double.valueOf(srcStrings[6].substring(0, 5));}Log.i("Show", String.valueOf(mdTotalStationCoord[2]));strData = "";}}}} catch (Exception e) {strData = "";}}

需要注意地方是,数据接收时,是断断续续从缓冲区取出来,不是一次性的。可能间隔就是几百毫秒。
这种时候,需要特别了解每种情况接收到最后的数据时什么样。找出每条完整数据的共性。

抓住主要特点,想到各种情况。
会遇到很多很坑的数据解析
这里只提供一种参考思路。

3,物联网一般数据解析

跟硬件那边传输数据,一般都是十六进制传输的数据,所以一般先解析出来十六进制的字符串后者十六进制的字符数组

收到原始数据:

byte[] buffer = new byte[] {104, 56, 56, 104, 0, 114, 120, 85, 52, 18, 67, 35, 1, 7, 0, 0, 0, 0, 12, 19, 120, 86, 52, 18, 12,

59, 120, 52, 18, 12, 38, 120, 86, 52, 18, 11, 89, 69, 35, 0, 2, -3, 23, 0, 0, 22};

/** * byte数组转换成16进制字符数组 *  * @param src * @return */public static String[] bytesToHexStrings(byte[] src) {if (src == null || src.length <= 0) {return null;}String[] str = new String[src.length];for (int i = 0; i < src.length; i++) {str[i] = String.format("%02X", src[i]);}return str;}


然后就是根据不同位数提取有用的数据

//总流量if (strResult.length != 0) {if (strResult[19].equalsIgnoreCase("0C") && strResult[20].equalsIgnoreCase("13")) {String strWater = strResult[24] + strResult[23] + strResult[22] + strResult[21];double dWater = Double.valueOf(strWater);mtextViewShow1.setText(String.valueOf(dWater/1000) + "m³");}//流速if (strResult[25].equalsIgnoreCase("0C") && strResult[26].equalsIgnoreCase("3B")) {String strFlow = strResult[30]+strResult[29]+strResult[28]+strResult[27];double dFlow = Double.valueOf(strFlow);mtextViewShow2.setText(String.valueOf(dFlow/1000) + "m³/h");}//温度if (strResult[37].equalsIgnoreCase("0B") && strResult[38].equalsIgnoreCase("59")) {String strTemp = strResult[41]+strResult[40]+strResult[39];double dTemp = Double.valueOf(strTemp);mtextViewShow5.setText(String.format("%.2f", dTemp/100) + "℃");}if (strResult[42].equalsIgnoreCase("02")&& strResult[43].equalsIgnoreCase("FD") && strResult[44].equalsIgnoreCase("17")) {String hexResult = StringUtil.reverseString(StringUtil.hexStringToBinary(strResult[45]));if(hexResult == null){return;}String str = hexResult.substring(5, 6);//0表示管道正常           倒数第三位if (str.equalsIgnoreCase("0")) {mtextViewShow3.setText("Normal");}//1表示空管;else if (str.equalsIgnoreCase("1")) {mtextViewShow3.setText("Empty");}// 最后两位String str1 = hexResult.substring(6, 8);//01 表示静止if (str1.equalsIgnoreCase("01") || str1.equalsIgnoreCase("11")) {mtextViewShow4.setText("Flowing");}//00 表示启动if (str1.equalsIgnoreCase("00")) {mtextViewShow4.setText("Start");}//10,11表示流动if (str1.equalsIgnoreCase("10")) {mtextViewShow4.setText("Stagnant");}}}

都是根据约定提取数据啦

最后附上一个常用进制转换工具类

package com.aufw.util;import java.io.ByteArrayOutputStream;public class StringUtil {    //  十六进制的字符串转换成byte数组public static byte[] HexCommandtoByte(byte[] data) {if (data == null) {return null;}int nLength = data.length; String strTemString = new String(data, 0, nLength);String[] strings = strTemString.split(" ");nLength = strings.length;data = new byte[nLength];for (int i = 0; i < nLength; i++) {if (strings[i].length() != 2) {data[i] = 00;continue;}try {data[i] = (byte)Integer.parseInt(strings[i], 16);} catch (Exception e) {data[i] = 00;continue;}}return data;}/** * byte数组转换成16进制字符数组 *  * @param src * @return */public static String[] bytesToHexStrings(byte[] src) {if (src == null || src.length <= 0) {return null;}String[] str = new String[src.length];for (int i = 0; i < src.length; i++) {str[i] = String.format("%02X", src[i]);}return str;}    /**     * 十六进制字符串装十进制     *      * @param hex     *            十六进制字符串     * @return 十进制数值     */    public static int hexStringToAlgorism(String hex) {    if (hex == null) {    return 0;}        hex = hex.toUpperCase();        int max = hex.length();        int result = 0;        for (int i = max; i > 0; i--) {            char c = hex.charAt(i - 1);            int algorism = 0;            if (c >= '0' && c <= '9') {                algorism = c - '0';            } else {                algorism = c - 55;            }            result += Math.pow(16, max - i) * algorism;        }        return result;    }// 十六进制的字符串转化为Stringprivate static String hexString = "0123456789ABCDEF";public static String decode(String bytes) {ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);// 将每2位16进制整数组装成一个字节for (int i = 0; i < bytes.length(); i += 2)baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));return new String(baos.toByteArray());}  /**     * 十六转二进制     *      * @param hex     *            十六进制字符串     * @return 二进制字符串     */    public static String hexStringToBinary(String hex) {       if (hex == null) {    return null;}        hex = hex.toUpperCase();        String result = "";        int max = hex.length();        for (int i = 0; i < max; i++) {            char c = hex.charAt(i);            switch (c) {            case '0':                result += "0000";                break;            case '1':                result += "0001";                break;            case '2':                result += "0010";                break;            case '3':                result += "0011";                break;            case '4':                result += "0100";                break;            case '5':                result += "0101";                break;            case '6':                result += "0110";                break;            case '7':                result += "0111";                break;            case '8':                result += "1000";                break;            case '9':                result += "1001";                break;            case 'A':                result += "1010";                break;            case 'B':                result += "1011";                break;            case 'C':                result += "1100";                break;            case 'D':                result += "1101";                break;            case 'E':                result += "1110";                break;            case 'F':                result += "1111";                break;            }        }        return result;    }        /**      * 倒置字符串      *       * @param str      * @return      */      public static String reverseString(String str)      {          char[] arr=str.toCharArray();          int middle = arr.length>>1;//EQ length/2          int limit = arr.length-1;          for (int i = 0; i < middle; i++) {              char tmp = arr[i];              arr[i]=arr[limit-i];              arr[limit-i]=tmp;          }          return new String(arr);      } }

关于物联网的解析数据可查看这个

android byte字节数组转换十六进制字符串(物联网开发总结)


1 0
原创粉丝点击