应用中需要上传用户图片,不想数据库单独维护图片的信息,想直接从编码定位到图片文件,又不想编码太长,所以需要压缩数字串。
/**
* 64进制和10进制的转换类
*
* @author
*
*/
public class compressEncodeing {
final static String PHOTOS_PREFIX = "H";
final static String DEFUALT_IMAGE_SUBFIX = ".jpg";
final static String PLACEHOLDER = "-";
final static String UNDERLINE = "_";
final static String SEPARATOR = "/";
final static String DOT = ".";
final static String[] IMAGES_TYPE = { "bmp", "gif", "jpg", "png" };
final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z', '+', '/', };
/**
* @param args
*/
public static void main(String[] args) {
String url = getEncodePhotoUrl(1234567890, "png");
System.out.println(url);
url = getDecodePhotoName(url + "_640x480.png");
System.out.println(url);
}
/**
* 根据 userID 返回图片的 URL 编码 编码规则,共四段组成
* 编码前:H(1位长相册类型)-1234567890(10位长用户ID)-1325137433192(13位毫秒)-2(1位随机码)-3
* (图片类型码) 编码后:H(1位长相册相册)19Bwbi(6位长用户ID)ji8m99E(7位毫秒)-n(1位随机码)
* 例:H19Bwbiji8m99E-n
*
* @param userID
* @param shift
* @return encoded url
*/
public static String getEncodePhotoUrl(long userID, String suffix) {
int suffixCode = -1;
for (int i = 0; i < IMAGES_TYPE.length; i++) {
if (IMAGES_TYPE[i].indexOf(suffix) != -1) {
suffixCode = i;
break;
}
}
return PHOTOS_PREFIX
+ prefixFormat(CompressNumber(userID, 6), 6)
+ prefixFormat(CompressNumber(System.currentTimeMillis(), 6), 7)
+ (CompressNumber((int) (Math.random() * 10), 6))
+ (suffixCode == -1 ? 0 : suffixCode);
}
/**
* 根据编码后的图片的 URL 返回真实的图片文件名 编码规则
* 解码前:H(1位长相册相册)19Bwbi(6位长用户ID)ji8m99E(7位毫秒)-n(2位随机码)_640x480(size).png(后缀)
* 解码后:H(1位长相册类型)/1234567890(10位长用户ID)/1325137433192(13位毫秒)23(2位随机码)
* 例:H19Bwbiji8m99E-n_640x480.png ->
* /H/1234567890/132513743319223_640x480.png
*
* @param url
* @return decoded photo file name
*/
public static String getDecodePhotoName(String url) {
// 必须是大于 16位
if (url == null || url.length() < 16)
return null;
String encodedUrl = url.substring(0, url.indexOf(UNDERLINE));
// 有效编码必须是 16 位
if (encodedUrl == null || encodedUrl.length() != 16)
return null;
String size = url.substring(url.indexOf(UNDERLINE), url.indexOf(DOT));
String suffix = url.substring(url.indexOf(DOT), url.length());
return encodedUrl.substring(0, 1) + SEPARATOR
+ UnCompressNumber(encodedUrl.substring(1, 7)) + SEPARATOR
+ UnCompressNumber(encodedUrl.substring(7, 14))
+ UnCompressNumber(encodedUrl.substring(14, 15)) + size
+ suffix;
}
/**
* 把10进制的数字转换成64进制
*
* @param number
* @param shift
* @return
*/
private static String CompressNumber(long number, int shift) {
char[] buf = new char[64];
int charPos = 64;
int radix = 1 << shift;
long mask = radix - 1;
do {
buf[--charPos] = digits[(int) (number & mask)];
number >>>= shift;
} while (number != 0);
return new String(buf, charPos, (64 - charPos));
}
/**
* 把64进制的字符串转换成10进制
*
* @param decompStr
* @return
*/
private static long UnCompressNumber(String decompStr) {
long result = 0;
for (int i = decompStr.length() - 1; i >= 0; i--) {
if (i == decompStr.length() - 1) {
result += getCharIndexNum(decompStr.charAt(i));
continue;
}
for (int j = 0; j < digits.length; j++) {
if (decompStr.charAt(i) == digits[j]) {
result += ((long) j) << 6 * (decompStr.length() - 1 - i);
}
}
}
return result;
}
/**
*
* @param ch
* @return
*/
private static long getCharIndexNum(char ch) {
int num = ((int) ch);
if (num >= 48 && num <= 57) {
return num - 48;
} else if (num >= 97 && num <= 122) {
return num - 87;
} else if (num >= 65 && num <= 90) {
return num - 29;
} else if (num == 43) {
return 62;
} else if (num == 47) {
return 63;
}
return 0;
}
/**
* 格式化文本,按固定长度,位数不够在前面补“-”
*
* @param soucre
* 原来的文本
* @param length
* 固定长度值
* @return String 格式化后文本
*/
public static String prefixFormat(String soucre, int length) {
//
return String.format("%" + length + "s", soucre).replaceAll(" ",
PLACEHOLDER);
}
}