此方法适用于数据固定分类展示
假设单个文件有6百多万的数据量(按行列存储500*13202),数据按类别可以分为5类
先说结果,原始数据量31.6M,压缩后文件是3K
按如下步骤进行处理
1.将所有数据划分为5类
List<Float> hResult = new ArrayList<>(500 * 13202);
byte[] bytes = new byte[500 * 13202];
for (int i = 500; i < 1000; i++) {
for (int j = 0; j < 13202; j++) {
// 存储数据,生成txt
hResult.add(NumberUtil.round(hdata[i][j], 4).floatValue());
// 将数据转换成byte[]
bytes[t++] = FileUtil.getGrade(NumberUtil.round(hdata[i][j], 4).floatValue(), gradeArray, -1f);
}
}
/**
* 0- <0.1的数据
* 1- 0.1=<x<0.2
* 2- 0.2=<x<0.3
* 3- 0.3=<x<0.4
* 4- 0.4=<x
* @param value 需要处理的值
* @param gradeArray 类别
* @param noDataValue 无效数据,可以指定,也可以不指定
* @return
*/
public static byte getGrade(float value, float[] gradeArray, float noDataValue) {
if (value == noDataValue) {
return 0;
}
byte num = 0;
for (int index = 0; index < gradeArray.length; ++index) {
if (index == gradeArray.length - 1) {
if (value >= gradeArray[index]) {
num = (byte) (index + 1);
}
} else if (value >= gradeArray[index] && value < gradeArray[index + 1]) {
num = (byte) (index + 1);
}
}
return num;
}
2.将分类后的数据进行压缩
// 获取压缩后的数据
List<Byte> compressByte = new ArrayList<>();
FileUtil.compressData(compressByte, bytes);
/**
* @describe:加密算法,获取总的结果
* @param:
* @param: result 加密后的值
* @param: dataArray 原始值
* @return: void
**/
public static void compressData(List<Byte> result, byte[] dataArray) {
byte num = dataArray[0];
int count = 0;
for (int i = 0; i < dataArray.length; i++) {
byte data = dataArray[i];
if ((int) data == (int) num) {
++count;
} else {
writeData(result, num, count);
num = data;
count = 1;
}
}
if (count == dataArray.length) {
writeData(result, num, count);
}
}
/**
* 解码的规律是以8位步长加载二进制作为一组,1组中从左数第一个不是1的是颜色组,颜色组右三位表示颜色,颜色个数的算法如下:
* 1.第一个颜色组到下一个颜色组之间算 组数
* 2.第一个颜色组中的数>>3然后<<7*(组数-组数所在位置(位置从1开始)) 得到最高位
* 3.除颜色组外组数的值(无符号位与运算127)<<7*(组数-组数所在位置)
* 4.最后一组的数也就是本身
* 5.个数还需要和列进行比较,不能超过列数
* byte数组1个字节,二进制占8位,颜色占3位
* 01111 111 去除颜色位,按16进制解码,找到下一个
*/
private static void writeData(List<Byte> result, byte value, int count) {
if (count < 16) {
byte num = (byte) ((count << 3) | value);
result.add(num);
} else if (count < 2048) {
byte num1 = (byte) ((count >> 7 << 3) | value);
result.add(num1);
byte num2 = (byte) ((count & (int) Byte.MAX_VALUE) | 128);
result.add(num2);
} else if (count < 262144) {
byte num1 = (byte) ((count >> 14 << 3) | value);
result.add(num1);
byte num2 = (byte) ((count >> 7 & (int) Byte.MAX_VALUE) | 128);
result.add(num2);
byte num3 = (byte) ((count & (int) Byte.MAX_VALUE) | 128);
result.add(num3);
} else if (count < 33554432) {
byte num1 = (byte) ((count >> 21 << 3) | value);
result.add(num1);
byte num2 = (byte) ((count >> 14 & (int) Byte.MAX_VALUE) | 128);
result.add(num2);
byte num3 = (byte) ((count >> 7 & (int) Byte.MAX_VALUE) | 128);
result.add(num3);
byte num4 = (byte) ((count & (int) Byte.MAX_VALUE) | 128);
result.add(num4);
} else {
if (count >= 1) {
return;
}
byte num1 = (byte) ((count >> 28 << 3) | value);
result.add(num1);
byte num2 = (byte) ((count >> 21 & (int) Byte.MAX_VALUE) | 128);
result.add(num2);
byte num3 = (byte) ((count >> 14 & (int) Byte.MAX_VALUE) | 128);
result.add(num3);
byte num4 = (byte) ((count >> 7 & (int) Byte.MAX_VALUE) | 128);
result.add(num4);
byte num5 = (byte) ((count & (int) Byte.MAX_VALUE) | 128);
result.add(num5);
}
}
3.存储压缩数据
// 存储二进制数据
String imageResultPath_h = "D:\\data\\cs.dat";
DataOutputStream out_h = new DataOutputStream(cn.hutool.core.io.FileUtil.getOutputStream(imageResultPath_h));
byte[] resultByte = new byte[compressByte.size()];
for (int j = 0; j < compressByte.size(); j++) {
resultByte[j] = compressByte.get(j);
}
out_h.write(resultByte, 0, compressByte.size());
out_h.flush();
out_h.close();
重点解释下writeData方法
writeData(List<Byte> result, byte value, int count)
result是最后的结果,value是类别值(0-4),count是类别的个数
byte 1字节在二进制中是8位 颜色位3位,数据标识占1位,value类别转化成二进制不超过3位,第一个字节先存储颜色位,颜色位占3位,数据和颜色字节区别是以每个字节中的第一位区别,颜色位字节第一位是0,数据位字节第一位是1
数据大小以n+4字节划分,n是7的倍数,0000,0000 000 0000 ,0000 000 0000 000 0000 .......,对应的int型数是最大值分别是15,2047,262143 .....
每次存储先从高位进行存储,每个字节是8位,每次位移是7的倍数,首位进行补充标识位,解析时间有规律可循
此方法进行数据传输即有加密的效果,又达到的数据量的压缩,后续经过改进可以适应很多数据类型。