ISO8583报文解析
在此只写了一个8583报文的拆包,组包其实也差不多的。
不多说直接上文件,
具体思路过程,在解析类里面写的有。
其中包含了四个文件
8583resp.txt报文
ISO8583medata配置文件
Bean8583Factory.java 8583配置文件解析类
Parse8583.java 8583报文解析类
8583报文
29 01 30 34 31 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 00 00 00 00
30 38 34 31 30 31 36 32 00 30 32 31 30 F2 3E 40
81 8E F0 80 00 00 00 00 00 10 00 00 E1 31 36 35
32 33 39 35 39 30 30 30 30 31 34 31 32 32 38 30
30 30 30 30 30 30 30 30 30 30 30 30 39 38 37 36
31 30 39 30 38 31 34 35 33 33 34 34 31 30 31 36
32 31 34 35 33 33 34 30 39 30 38 33 30 30 38 30
31 30 35 36 30 31 33 30 30 30 38 36 33 30 34 30
32 35 30 30 38 36 33 30 34 30 30 30 30 30 30 30
30 30 30 34 31 30 31 36 32 35 35 35 33 32 32 30
30 37 37 37 37 37 37 37 37 30 32 38 30 30 30 30
31 30 39 20 20 20 20 20 B4 FA C0 ED C6 F3 D2 B5
CD F8 D2 F8 D7 A8 D3 C3 B2 E2 CA D4 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
32 35 30 30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 31 35 36 30 38
36 33 30 34 30 30 30 30 30 30 30 30 31 38 20 20
20 20 20 20 20 20 20 20 20 20 B2 E2 CA D4 31 34
30 39 35 4E 20 20 30 30 30 31 30 31 39 35 33 37
37 30 30 30 30 30 30 35 30 30 30 30 20 20 30 30
30 30 30 30 20 20 30 30 32 20 2D 30 30 35 34 36
37 32 35 31 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
31 30 33 43 34 44 45 44 33 37
8583配置文件
<?xml version="1.0" encoding="utf-8"?>
<sdoroot package_type="iso8583" store-mode="GBK">
<H1 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
<H2 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
<H3 type="string" length="4" isHeader="true" encoding="GBK"/>
<H4 type="string" length="11" isHeader="true" encoding="GBK"/>
<H5 type="string" length="11" isHeader="true" encoding="GBK"/>
<H6 type="string" length="3" isHeader="true" encoding="GBK" isBCD="true"/>
<H7 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
<H8 type="string" length="8" isHeader="true" encoding="GBK" />
<H9 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
<MsgType type="string" length="4" encoding="GBK"/>
<bitmap1 length="8" type="bitmap"/>
<bitmap2 length="8" type="bitmap"/>
<F2 type="string" length="19" variable_flag="2" field_index="2" encoding="GBK"/>
<F3 type="string" length="6" field_index="3" encoding="GBK"/>
<F4 type="string" length="12" field_index="4" encoding="GBK"/>
<F6 type="string" length="12" field_index="6" encoding="GBK"/>
<F7 type="string" length="10" field_index="7" encoding="GBK"/>
<F10 type="string" length="8" field_index="10" encoding="GBK"/>
<F11 type="string" length="6" field_index="11" encoding="GBK"/>
<F12 type="string" length="6" field_index="12" encoding="GBK"/>
<F13 type="string" length="4" field_index="13" encoding="GBK"/>
<F14 type="string" length="4" field_index="14" encoding="GBK"/>
<F15 type="string" length="4" field_index="15" encoding="GBK"/>
<F18 type="string" length="4" field_index="18" encoding="GBK"/>
<F22 type="string" length="3" field_index="22" encoding="GBK"/>
<F23 type="string" length="3" field_index="23" encoding="GBK"/>
<F25 type="string" length="2" field_index="25" encoding="GBK"/>
<F26 type="string" length="2" field_index="26" encoding="GBK"/>
<F28 type="string" length="9" field_index="28" encoding="GBK"/>
<F32 type="string" length="11" variable_flag="2" field_index="32" encoding="GBK"/>
<F33 type="string" length="11" variable_flag="2" field_index="33" encoding="GBK"/>
<F35 type="string" length="37" variable_flag="2" field_index="35" encoding="GBK"/>
<F36 type="string" length="104" variable_flag="3" field_index="36" encoding="GBK"/>
<F37 type="string" length="12" field_index="37" encoding="GBK"/>
<F38 type="string" length="6" field_index="38" encoding="GBK"/>
<F39 type="string" length="2" field_index="39" encoding="GBK"/>
<F41 type="string" length="8" field_index="41" encoding="GBK"/>
<F42 type="string" length="15" field_index="42" encoding="GBK"/>
<F43 type="string" length="40" field_index="43" encoding="GBK"/>
<F44 type="string" length="25" variable_flag="2" field_index="44" encoding="GBK"/>
<F47 type="string" length="100" variable_flag="3" field_index="47" encoding="GBK"/>
<F48 type="string" length="400" variable_flag="3" field_index="48" encoding="GBK"/>
<F49 type="string" length="3" field_index="49" encoding="GBK"/>
<F51 type="string" length="3" field_index="51" encoding="GBK"/>
<F52 type="string" length="8" field_index="52" encoding="GBK"/>
<F53 type="string" length="16" field_index="53" encoding="GBK"/>
<F54 type="string" length="40" variable_flag="3" field_index="54" encoding="GBK" />
<F55 type="string" length="300" variable_flag="3" field_index="55" encoding="GBK" />
<F57 type="string" length="100" variable_flag="3" field_index="57" encoding="GBK" />
<F60 type="string" length="100" variable_flag="3" field_index="60" encoding="GBK"/>
<F61 type="string" length="200" variable_flag="3" field_index="61" encoding="GBK"/>
<F62 type="string" length="200" variable_flag="3" field_index="62" encoding="GBK"/>
<F70 type="string" length="3" field_index="70" encoding="GBK"/>
<F90 type="string" length="42" field_index="90" encoding="GBK"/>
<F91 type="string" length="1" field_index="91" encoding="GBK"/>
<F96 type="string" length="8" field_index="96" encoding="GBK"/>
<F100 type="string" length="11" variable_flag="2" field_index="100" encoding="GBK"/>
<F102 type="string" length="32" variable_flag="2" field_index="102" encoding="GBK"/>
<F103 type="string" length="32" variable_flag="2" field_index="103" encoding="GBK"/>
<F108 type="string" length="32" variable_flag="3" field_index="108" encoding="GBK"/>
<F121 type="string" length="100" variable_flag="3" field_index="121" encoding="GBK"/>
<F122 type="string" length="50" variable_flag="3" field_index="122" encoding="GBK"/>
<F123 type="string" length="400" variable_flag="3" field_index="123" encoding="GBK"/>
<F128 type="string" length="8" field_index="128" encoding="GBK"/>
</sdoroot>
8583配置类
package com.handle8583; import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader; public class Bean8583Factory { private static Map<String,Properties> map = new HashMap<String, Properties>(); private static Bean8583Factory instance = null; private static Log log = LogFactory.getLog(Bean8583Factory.class); public static Bean8583Factory getInstance(){
if(null == instance){
map.clear();
instance = new Bean8583Factory();
}
return instance;
} private Bean8583Factory(){
init();
} public void init() {
System.out.println("加载8583配置开始"); File f = new File("D:/workspace/springweb/src/com/handle8583/ISO8583medata.xml");
if ((f.exists()) && (f.isFile())) {
SAXReader reader = new SAXReader();
try {
Iterator<Node> iterator2;
Document doc = reader.read(f);
List obj = doc.getRootElement().elements();
if (obj == null) {
return;
}
Iterator<Node> iterator = obj.iterator();
while (iterator.hasNext()) {
Node imetadata = iterator.next();
Properties pop = new Properties(); Node isHeader = imetadata.selectSingleNode("@isHeader");
if(null != isHeader){
pop.setProperty("isHeader", isHeader.getText());
} Node isBCD = imetadata.selectSingleNode("@isBCD");
if(null != isBCD){
pop.setProperty("isBCD", isBCD.getText());
} Node type = imetadata.selectSingleNode("@type");
if(null != type){
pop.setProperty("type", type.getText());
} Node length = imetadata.selectSingleNode("@length");
if(null != length){
pop.setProperty("length", length.getText());
} Node variable_flag = imetadata.selectSingleNode("@variable_flag");
if(null != variable_flag){
pop.setProperty("variable_flag", variable_flag.getText());
} Node field_index = imetadata.selectSingleNode("@field_index");
if(null != field_index){
pop.setProperty("field_index", field_index.getText());
} Node encoding = imetadata.selectSingleNode("@encoding");
if(null != encoding){
pop.setProperty("encoding", encoding.getText());
} pop.setProperty("name", imetadata.getName());
map.put(imetadata.getName(),pop); }
} catch (DocumentException e) {
e.printStackTrace();
System.out.println("加载8583配置异常");
}
}
System.out.println("加载8583配置完成");
} public Map<String, Properties> getMap() {
return map;
} public Properties getFieldPropertie(String fieldName) {
return map.get(fieldName);
} public String getFieldPropertieVal(String fieldName,String propertieName) {
return map.get(fieldName).getProperty(propertieName);
} }
8583解析类
package com.handle8583; import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import com.parseToString.FileTools;
/*
* @description:
* 准备包含8583报文头、报文类型标识、位图、报文体各域的ISO8583metadata.xml配置文件
* 准备8583十六进制报文
* 使用SAXReader读取ISO8583metadata.xml文件,将文件中的内容解析成Map<String,Properties>
* 使用文件输入流读取8583十六进制报文到字节数组输出流,字节数组输出流转换为字节数组
* 将字节数组转换成字符串,此刻字符串的内容与十六进制里的内容完全一致,并将字符串换行、空去掉
* 将字符串转换成字节数组(即将十六进制转换成十进制的字节数组)
* 解析报文头(根据ISO8583metadata.xml中:isBCD确定编码、length确定长度、encoding确定编码、name作为标签名。现根据长度截取,再判断isBCD编码,根据相应的编码解码。)
* 解析报文类型标识(根据长度,byte子数组,根绝对应的encoding编码进行解码)
* 解析位图(判断第一个字节的二进制最高位是否为1,为1则使用扩展位图,为0则不使用扩展位图;根据长度获取byte字数组,转换成对应的二进制;根据二进制判断存在哪些域有值)
* 解析报文体(将存在的域循环进行处理:判断是否变长,如果变长,先获取变长所表示的长度值,比如n..11(LLVAR)为两位变长,有两个字节表示长度,先拿两个字节计算本域所占几个字节,再获取相应字节数,再根据encoding编码进行解码;如果非变长,直接根据length获取长度,再根据encoding编码进行解码)
* 将解析完成的8583报文信息所在的Map排序,便于打印阅览(此处不再说明,看代码即可)
*
* @warn注意点
* 对于0~9的数字
* 十六进制转换成十进制,相应于BCD码转换成十进制
* 一个十六进制相当于一个byte,相当于两个[0,9]
*
* @see
* 8583报文拆组包关键点:
* 报文头各域、表问类型标识、位图或者报文体域所使用的编码方式,比如BCD编码还是普通的十六进制
* 位图的使用
* 报文体域的变长处理
*
* @see
* 拆组包8583报文需要对于编码和解码、进制转换、字符集有一个充分和系统的了解
*/
public class Parse8583 {
static int currentIndex = 0;
static Map<String, Properties> map = Bean8583Factory.getInstance().getMap();
public static void main(String[] args) throws UnsupportedEncodingException {
//获取8583报文
byte[] resp = FileTools.readContent("D:/workspace/springweb/src/com/handle8583/8583resp.txt");
String str = new String(resp).trim().replace("\r\n", "").replace("\r","").replace("\n", "").replace(" ", "");
//将报文解析成字节数组
byte[] retByte = parseTo8583bytes(str);
//解析8583报文体
Map<String,String> fieldMap = parse8583(retByte);
//获取有序的keys
List<String> keyList = getKeyList(fieldMap);
//输出各域信息
for(String key:keyList){
System.out.println("["+key+"] = "+fieldMap.get(key));
}
} // 报文处理函数
private static Map<String, String> parse8583(byte[] byteArr)
throws UnsupportedEncodingException {
Map<String,String> fieldMap = new HashMap<String,String>();
//获取报文头信息
parseHeaders(byteArr, fieldMap);
// 获取MsgType
parseMsgType(byteArr, fieldMap);
// 获取位图
String bitMap1_value = getBitMap(byteArr);
fieldMap.put("F1", bitMap1_value);
// 根据位图判断存在哪些域及获取域的值
parseFields(byteArr, fieldMap, bitMap1_value);
// 返回
return fieldMap;
}
//获取报文头信息
private static void parseHeaders(byte[] byteArr,Map<String, String> fieldMap)
throws UnsupportedEncodingException {
for(int i=1;i<=10;i++){
Properties headProperties = map.get("H"+i);
if(headProperties == null) continue; int head_length = Integer.parseInt(headProperties.getProperty("length"));
byte[] head_value_byte = new byte[head_length];
System.arraycopy(byteArr, currentIndex, head_value_byte, 0, head_length);
currentIndex += head_length; String isBCD = headProperties.getProperty("isBCD");
if("true".equals(isBCD)){
String head_value = bcd_bytes_to_String(head_value_byte);
fieldMap.put(headProperties.getProperty("name"), head_value);
}else{
String head_value = new String(head_value_byte, headProperties.getProperty("encoding"));
fieldMap.put(headProperties.getProperty("name"), head_value);
}
}
}
//bcd_bytes_to_String
private static String bcd_bytes_to_String(byte[] bytes){
StringBuffer sb = new StringBuffer(bytes.length*2);
for(int i=0;i<bytes.length;i++){
sb.append(String.valueOf((int)bytes[i]));
}
return sb.toString();
}
//解析各个域
private static void parseFields(byte[] byteArr,Map<String, String> fieldMap,String bitMap1_value_2) throws UnsupportedEncodingException {
List<Integer> exitFieldList = getExitField(bitMap1_value_2);
// 获取各域值
for(int i=0;i<exitFieldList.size();i++){
int field = exitFieldList.get(i);
Properties fieldProperties = map.get("F"+field);
//如果不存在,跳过
if(fieldProperties == null)continue; String field_variable_flag = fieldProperties.getProperty("variable_flag");
if(field_variable_flag == null || "".equals(field_variable_flag)){
int field_length = Integer.parseInt(fieldProperties.getProperty("length"));
byte[] field_value_byte = new byte[field_length];
System.arraycopy(byteArr, currentIndex, field_value_byte, 0, field_length);
currentIndex += field_length;
String field_value = new String(field_value_byte, fieldProperties.getProperty("encoding"));
fieldMap.put(fieldProperties.getProperty("name"), field_value);
}else{
//先获取变长域的长度值
int variable_flag_length = Integer.parseInt(field_variable_flag);
byte[] variable_flag_byte = new byte[variable_flag_length];
System.arraycopy(byteArr, currentIndex, variable_flag_byte, 0, variable_flag_length);
currentIndex += variable_flag_length;
String variable_flag_value = new String(variable_flag_byte, fieldProperties.getProperty("encoding"));
//再获取变长域的真实值
int field_length = Integer.parseInt(variable_flag_value);
byte[] field_value_byte = new byte[field_length];
System.arraycopy(byteArr, currentIndex, field_value_byte, 0, field_length);
currentIndex += field_length;
String field_value = new String(field_value_byte, fieldProperties.getProperty("encoding"));
fieldMap.put(fieldProperties.getProperty("name"), field_value);
}
}
}
//获取二进制位图字符串
private static String getBitMap(byte[] byteArr) {
Properties bitMap1 = map.get("bitmap1");
int bitMap1_length = Integer.parseInt(bitMap1.getProperty("length"));
byte[] bitMap1_value_byte = new byte[bitMap1_length];
System.arraycopy(byteArr, currentIndex, bitMap1_value_byte, 0,bitMap1_length);
currentIndex += bitMap1_length;
String bitMap1_value_2 = binary(bitMap1_value_byte, 2);
if (bitMap1_value_2.startsWith("1")) {
Properties bitMap2 = map.get("bitmap2");
int bitMap2_length = Integer.parseInt(bitMap2.getProperty("length"));
byte[] bitMap2_value_byte = new byte[bitMap2_length];
System.arraycopy(byteArr, currentIndex, bitMap2_value_byte, 0,bitMap2_length);
currentIndex += bitMap2_length;
String bitMap2_value_2 = binary(bitMap2_value_byte, 2);
bitMap1_value_2 += bitMap2_value_2;
}
return bitMap1_value_2;
}
//解析MsgType
private static void parseMsgType(byte[] byteArr,Map<String, String> mapRet)
throws UnsupportedEncodingException {
Properties msgType = map.get("MsgType");
int msgType_length = Integer.parseInt(msgType.getProperty("length"));
byte[] msgType_value_byte = new byte[msgType_length];
System.arraycopy(byteArr, currentIndex, msgType_value_byte, 0,msgType_length);
currentIndex += msgType_length;
String msgType_value = new String(msgType_value_byte, msgType.getProperty("encoding"));
mapRet.put("F0", msgType_value);
}
//根据二进制位图字符串获取存在的域
private static List<Integer> getExitField(String bitMap2String) {
List<Integer> exitFieldList = new ArrayList<Integer>();
for (int i=2;i<=bitMap2String.length();i++) {
int field_index = Integer.parseInt(String.valueOf(bitMap2String.charAt(i-1)));
if (field_index == 1) {
exitFieldList.add(i);
}
}
return exitFieldList;
}
//将报文解析成字节数组
private static byte[] parseTo8583bytes(String str) {
String value = null;
byte[] retByte = new byte[str.length() / 2];
for (int i = 0; i < str.length(); i = i + 2) {
value = str.substring(i, i + 2);
retByte[i / 2] = (byte) Integer.parseInt(value, 16);
}
return retByte;
}
//获取有序的keys
private static List<String> getKeyList(Map<String, String> fieldMap) {
Set<String> keySet = fieldMap.keySet();
List<String> keyList = new ArrayList<String>(keySet);
Collections.sort(keyList, new Comparator<String>(){
@Override
public int compare(String str1, String str2) {
// TODO Auto-generated method stub
Integer value1 = Integer.parseInt(str1.substring(1));
Integer value2 = Integer.parseInt(str2.substring(1));
return value1.compareTo(value2);
}});
Collections.sort(keyList, new Comparator<String>(){
@Override
public int compare(String str1, String str2) {
// TODO Auto-generated method stub
char value1 = str1.charAt(0);
char value2 = str2.charAt(0);
return value1 < value2 ? 1 : 0;
}});
return keyList;
}
//将字节数组转换成二进制字符串
private static String binary(byte[] bytes, int radix) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(byteToBit(b));
}
return sb.toString();
}
/**
* Byte转Bit
*/
private static String byteToBit(byte b) {
return "" + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
} }
ISO8583报文解析的更多相关文章
- [性能测试]:ISO8583报文解析实例
现在我们有ISO8583报文如下(十六进制表示法): 60 00 03 00 00 60 31 00 31 07 30 02 00 30 20 04 C0 20 C0 98 11 00 00 00 0 ...
- 【8583】ISO8583报文解析
ISO8583报文(简称8583包)又称8583报文,是一个国际标准的包格式,最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分. [报文格式] POS终端上送POS中心的消息报文结构 ...
- 银联ISO8583报文解析过程
主密钥: aabbccddeeff11223344556677889900 1.从签到报文中获取工作密钥,包括MACKEY明文,PINKEY明文 签到: 12-03-31 16:38:09----&g ...
- (转载)解析ISO8583报文实例
本篇文章参考了中国银联POS终端规范,所以如有不明白的可以去我的资源里面下载. 现在我们有ISO8583报文如下(十六进制表示法): 60 00 03 00 00(前五个字节为TPDU) 60 31 ...
- 解析ISO8583报文实例
http://www.cnblogs.com/1971ruru/archive/2012/12/10/2811549.html 本篇文章参考了中国银联POS终端规范,所以如有不明白的可以去我的资源里面 ...
- ISO8583报文协议
最开始时,金融系统只有IBM这些大的公司来提供设备,象各种主机与终端等.在各个计算机设备之间,需要交换数据.我们知道数据是通过网络来传送的,而在网络上传送的数据都是基于0或1这样的二进制数据,如果没有 ...
- 轻松掌握ISO8583报文协议
http://www.itpub.net/thread-419521-1-1.html 我刚进入金融行业时,就知道了IS08583报文协议,我想可能我还没进入这个行业都已经听过了,可知ISO8583的 ...
- 报文解析及CRC类
/// <summary> /// 报文解析转换类 /// </summary> public class DatagramConvert { public static En ...
- 基于DPI(深度报文解析)的应用识别
一.概述 1.DPI(Deep packet inspection,深度报文解析) 所谓“深度”是和普通的报文分析层次相比较而言的,“普通报文检测”仅分析IP包4 层以下的内容,包括源地址.目的地址. ...
随机推荐
- Windows server 2008 上部署 MVC (NopCommerce 3.4)网站
自己用开源框架做了个商城,该框架是基于mvc4的,本地编译通过,运行一切正常,关于发布遇到了好几个问题. 本地: IIS7.5. VS2013 总结后发现只需要设置两个问题,就不会有那些古怪的问题:什 ...
- <Chapter 2>2-2.开发应用(developing the Application)
一个App Engine应用对网络请求做出响应.它是通过调用请求处理器(quest handlers)来实现的,接受请求参数并返回响应的程序.对于来自请求URL上的请求,App Engine通过一个配 ...
- SRM DIV1 500pt DP
SRM 501 DIV1 500pt SRM 502 DIV1 500pt SRM 508 DIV1 500pt SRM 509 DIV1 500pt SRM 511 DIV1 500pt SRM 5 ...
- 安装 RabbitMQ C#使用-摘自网络(包括RabbitMQ的配置)
1.什么是RabbitMQ.详见 http://www.rabbitmq.com/ . 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源的操作,放入队列,再由另外一个线程,去异步处理 ...
- COS回应7大质疑
Apple过于封闭,没啥朋友,这家伙应该比较高傲,曾和Intel,IBM and so on..一起玩过!Google过于开放,狐朋狗友,友人泛滥,殃及ecosystem,弊端已显,祸水将至.COS奉 ...
- POJ 3159 Candies(差分约束,最短路)
Candies Time Limit: 1500MS Memory Limit: 131072K Total Submissions: 20067 Accepted: 5293 Descrip ...
- Quality Center配置邮箱服务
Quality Center上要配置二个地方 mail direct pro配置 DNS地址是本机的地址就好了,不需要真实的DNS地址 SMTP端口使用普通的25就好了,不需要使用SSL的·465端口 ...
- myeclipse内存配置
配置文件路径:D:\work\myeclipse\MyEclipse for Spring 10\myeclipseforspring.ini 替换以下内容即可 -vmargs-Xmx768m-XX: ...
- 关于block以及__bridge的一些笔记
问题概要 _block是否是一个OC对象? __bridge相关. _block是否是一个OC对象? 结论 一般来说,block可以看做一个OC对象,但是在编译器底层,block又可以被细分为bloc ...
- java获取照片相关属性
package test; import java.io.File; import java.util.Iterator; import com.drew.imaging.jpeg.JpegMetad ...