定长报文简介
系统与系统按约定格式进行信息交互的字符串,称为报文。通常的格式有定长字符串和XML字符串。这里主要介绍一下定长字符串。
定长字符串,就是报文要素按固定顺序,固定长度组成一个报文字符串。这里的定长通常是指固定长度。固定的长度按字节计算。
定长字符串报文结构
- 定长字符串由报文要素组成,报文要素按位置表示具体的业务含义
- 报文要素包含3个内容:业务含义,固定长度(也是最大长度),要素值
- 对于要素值不够最大长度的情况,要填充指定字符以达到固定长度
- 对于包含中文的要素,要先指定信息交互的字符集,才能确定要素值的长度
GBK : 一个中文算两个字节
UTF-8 : 一个中文算3个字节
组定长报文的优化思路
组定长报文的核心方法,我个人觉得是拼接填充字符串的方法。
常用方法是逐个拼接
- 逐个拼接,时间复杂度O(n)
/**
* 右补空格
* @param padLen 填充长度
* @param fieldValue 要素值
* @return
*/
public static String paddingSpaces(int padLen, String fieldValue) {
if(padLen <= 0){
return fieldValue;
}
if (fieldValue == null){
fieldValue = "";
}
StringBuilder fixedValue = new StringBuilder(fieldValue);
while (padLen-- > 0) {
fixedValue.append(" ");
}
return fixedValue.toString();
}
- 扩展一下思路,为什么不可以2个2个拼呢,完成可以啊,时间复杂度O(n/2)
/**
* 右补空格,一次补两个空格
* @param padLen 填充长度
* @param fieldValue 要素值
* @return
*/
public static String paddingTwoSpaces(int padLen, String fieldValue) {
if(padLen <= 0){
return fieldValue;
}
if (fieldValue == null){
fieldValue = "";
}
StringBuilder fixedValue = new StringBuilder(fieldValue);
//要把填充长度先做成整倍数。
//这里是一次拼2个,做成偶数就可以了
//一次拼多于两个,要先在这里处理成整倍数
if (((padLen & 1) == 1)){
//补空格数为奇数,先补一个空格,变成偶数
fixedValue.append(" ");
padLen--;
}
while (padLen > 0) {
fixedValue.append(" ");//一次拼两个个空格
padLen -= 2;
}
return fixedValue.toString();
}
这个方法效率直接提高一倍☺,当然还可以继续扩展,一次拼3个,拼4次,本质都是一样的思路。要注意的一点,就是要把填充长度先做成整倍数。
- 上面的方法效率虽然提高了不少,但是时间复杂度数量级还是O(n),能不能进一步提高呢?
可以在系统启动时,先初始化一个Map,key是长度,value是对应长度的字符串。这样每次拼字符串时,先从Map中取,没有再拼接。通常初始化长度从1到20个这样的字符串,就足够使用,很少有报文要素需要补超过20个填充字符的
//初始化1-20个字符串供使用,这个可以根据需要调整
private static int cachedCount = 20;
//长字符串缓存开关,填充长度超过 cachedCount 时使用
private static boolean longSpaceCacheSwitch = false;
//初始化Map
private static Map<Integer, String> spaceCacheMap = new HashMap<Integer, String>();
static {
//初始化方法
//也可以定义成一个静态方法,系统启动时调用,以完成初始化
StringBuilder space = new StringBuilder(" ");
//1到20个字符串(空格)
for (int i = 1; i <= cachedCount; i++) {
spaceCacheMap.put(i, space.toString());
space.append(" ");
}
}
/**
* 使用缓存字符串Map,完成拼接
* @param padLen 填充长度
* @param fieldValue 要素值
* @return
*/
public static String paddingSpacesByCache(int padLen, String fieldValue){
if(padLen <= 0){
return fieldValue;
}
if (fieldValue == null){
fieldValue = "";
}
StringBuilder fixedValue = new StringBuilder(fieldValue);
String tmpValue = spaceCacheMap.get(padLen);
if(tmpValue != null){
//长度小于cachedCount,spaceCacheMap可以直接获取到
return fixedValue.append(tmpValue).toString();
}
//以下是填充长度大于cachedCount时的情况,
//这种情况应该很少,取决于cachedCount的设定
int tmpLen = padLen;
String spaces = spaceCacheMap.get(cachedCount);
do {
//一次拼20(cachedCount)个,
fixedValue.append(spaces);
padLen -= cachedCount;
} while (padLen >= cachedCount);
if(padLen > 0){
//填充长度不是cachedCount整倍数,要补上不足的部分
fixedValue.append(spaceCacheMap.get(padLen));
}
if(longSpaceCacheSwitch){
//缓存长文本字符串
//长度超过 cachedCount 时,把它添加到 spaceCacheMap 中,供下次使用
spaceCacheMap.put(tmpLen, fixedValue.toString());
}
return fixedValue.toString();
}
这个方法基本上可以达到O(1)的时间复杂度。