Android 压缩字符串 方便二维码传输

客户端中通过二维码传输数据的情况较多,但是直接传输可能因为数据过长导致二维码生成的太密不好扫描。

可以使用GZIP把字符串缩短进行传输,下面直接看代码

public class GZipUtils {
    public static String compress(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = null;
        try {
            gzip = new GZIPOutputStream(out);
            gzip.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (gzip != null) {
                try {
                    gzip.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return android.util.Base64.encodeToString(out.toByteArray(),android.util.Base64.NO_WRAP);
        //return new String(Base64.getEncoder().encode(out.toByteArray()));
    }

    /**
     * 使用gzip解压缩
     *
     * @param compressedStr 压缩字符串
     */
    public static String uncompress(String compressedStr) {
        if (compressedStr == null) {
            return null;
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = null;
        GZIPInputStream ginzip = null;
        byte[] compressed = null;
        String decompressed = null;
        try {
           // compressed = Base64.getDecoder().decode(compressedStr);
            compressed = android.util.Base64.decode(compressedStr,android.util.Base64.NO_WRAP);
            in = new ByteArrayInputStream(compressed);
            ginzip = new GZIPInputStream(in);
            byte[] buffer = new byte[1024];
            int offset = -1;
            while ((offset = ginzip.read(buffer)) != -1) {
                out.write(buffer, 0, offset);
            }
            decompressed = out.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ginzip != null) {
                try {
                    ginzip.close();
                } catch (IOException ignored) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ignored) {
                }
            }
            try {
                out.close();
            } catch (IOException ignored) {
            }
        }
        return decompressed;
    }

}

测试一下:

    private fun test() {
        logDebug("--------------开始任务---------------------")
        val str =
            "qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#\$%^&*()_+`¥……——+|《》?,./城市 姓名"

        val compress = GZipUtils.compress(str)
        logDebug("compress = " + compress)
        val uncompress = GZipUtils.uncompress(compress)
        logDebug("uncompress = " + uncompress)

        logDebug("--------------任务结束---------------------")
    }

打印结果:

2022-09-08 10:27:55 --------------开始任务---------------------
compress = H4sIAAAAAAAAACssTy0qqSzNzC9ILE5JS8/Iys6pqkguS8rLNTA0MjYxNTO3sKxTdFBWUY1T09LQjNdOOLT0UcMyMJoCRNo1jxu6Hjd0v98zX0dP/+n8vqc7mhSeLp/8dEJv4ajRo0aPGk2K0QBuPT1YjgMAAA==
uncompress = qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名
2022-09-08 10:27:55任务结束---------------------

可以看到整个过程在1s内。

java和Android中的差异

java中的import java.util.Base64 (在Android中使用需要api>26)

Base64.getEncoder().encode(out.toByteArray())
Base64.getDecoder().decode(compressedStr)
等同于
Android的import android.util.Base64
Base64.encodeToString(out.toByteArray(),Base64.NO_WRAP);
Base64.decode(compressedStr,Base64.NO_WRAP)
可以直接使用Android包中自带的。

android包中的第二个参数:Base64.NO_WRAP 有好几种类型
  • DEFAULT 默认模式
  • CRLF 指示行的编码器标志位用CRLF替代LF
  • NO_CLOSE 传递给Base64OutputStream标记以指示它本身关闭时不应关闭它正在包装的输出流
  • NO_PADDING 省略末尾填充的’='字符
  • NO_WRAP 省略所有的终止符
  • URL_SAFE URL和文件名安全方式,替换其中不符合url安全的字符如+和/

需要注意的是,在android.util.Base64源码 发现Encoder有以下一行注释

static class Encoder extends Coder {
        /**
         * Emit a new line every this many output tuples.  Corresponds to
         * a 76-character line length (the maximum allowable according to
         * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
         */
       

大意就是超过76字符就会自动换一行
在对接其他平台时,有些平台使用的base64对换行后的字符串不一定能正确decode,所以需要将

android.util.Base64.encodeToString(input, Base64.DEFAULT);

换成

android.util.Base64.encodeToString(input, Base64.NO_WRAP);

我们来写个简单的例子对比下DEFAULT、NO_PADDING、NO_WRAP和URL_SAFE,看看这几种区别

    public static void test() {
        String str = "qwertyuiopasdfghjklzxcvbnm0123456789~!@#$%^&*()_+`¥……——+|《》?,./城市 姓名";
        byte[] byteStr = str.getBytes(StandardCharsets.UTF_8);
        String encode_DEFAULT = android.util.Base64.encodeToString(byteStr, android.util.Base64.DEFAULT);
        String encode_NO_PADDING = android.util.Base64.encodeToString(byteStr, android.util.Base64.NO_PADDING);
        String encode_NO_WRAP = android.util.Base64.encodeToString(byteStr, android.util.Base64.NO_WRAP);
        String encodeURL_SAFE = android.util.Base64.encodeToString(byteStr, android.util.Base64.URL_SAFE);


        Log.v("wlike","encode_DEFAULT = "+encode_DEFAULT);
        Log.v("wlike","encode_NO_PADDING = "+encode_NO_PADDING);
        Log.v("wlike","encode_NO_WRAP = "+encode_NO_WRAP);
        Log.v("wlike","encodeURL_SAFE = "+encodeURL_SAFE);


    }

打印结果:
在这里插入图片描述
相对于DEFAULT比较,我们可以看见
NO_PADDING只是将末尾自动补全的=号去除了
NO_WRAP去除了换行,输出始终为一整行
URL_SAFE将结果中的+变成-

总结:
1.在android客户端里自己加解码,只要encode和decode使用对应的flag即可。encode时flag为Base64.URL_SAFE,decode的flag必须为Base64.URL_SAFE。

2.如果需要和第三方对接时,因为一般第三方http请求时会主动对参数和参数值urlencode 防止乱码,所以不需要再处理+等字符,直接使用NO_WRAP来encode。如果是自己封装的http请求,没有对参数和参数值urlencode,则需要在请求时对参数和参数值urlencode下。

更多:
android.util.Base64使用
java实现生成二维码并压缩内容
Gzip在线转换测试

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆啦A梦z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值