• 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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    测试一下:

        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("--------------任务结束---------------------")
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    打印结果:

    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任务结束---------------------
    
    • 1
    • 2
    • 3
    • 4

    可以看到整个过程在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
             * RFC 2045).
             */
           
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

    换成

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

    我们来写个简单的例子对比下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);
    
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    打印结果:
    在这里插入图片描述
    相对于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在线转换测试

  • 相关阅读:
    centeros7系统安装指定版本的mongodb数据库
    《从0开始写一个微内核操作系统》4-关于mmu
    或许你也想做一个这样的动态魔方吗?
    2022-08-02 C++并发编程(五)
    谷歌插件将网页转图片
    零基础自学Java的网站有哪些?
    【BOOST C++】教程4:常量和宏
    Spring Boot : Mybatis 执行原理分析
    Spring中事务的几种失效场景
    MinIO可视化的对象存储服务
  • 原文地址:https://blog.csdn.net/zx_android/article/details/126758761