fastjson深度源码解析- 序列化(二) - 序列化字节和字符串解析

本文深入解析fastjson的SerializeWriter,详细介绍了序列化16进制字节数组、byte字节数组、字符串、字符数组、列表字符串以及包含特殊字符的字符串的过程,涉及base64编码、ascii转换和特殊字符处理。
摘要由CSDN通过智能技术生成

SerializeWriter成员函数

序列化16进制字节数组

    public void writeHex(byte[] bytes) {
        /** 计算总共字符长度, 乘以2 代表一个字符要占用2字节, 3代表要添加 x 和 前后添加' */
        int newcount = count + bytes.length * 2 + 3;
        if (newcount > buf.length) {
            if (writer != null) {
                char[] chars = new char[bytes.length + 3];
                int pos = 0;
                chars[pos++] = 'x';
                chars[pos++] = '\'';

                for (int i = 0; i < bytes.length; ++i) {
                    byte b = bytes[i];

                    int a = b & 0xFF;
                    /** 取字节的高四位 1111 0000*/
                    int b0 = a >> 4;
                    /** 取字节的低四位 0000 1111*/
                    int b1 = a & 0xf;

                    /** 索引低索引存储字节高位
                     *  如果4位表示的数字是 0~9, 转换为ascii的 0~9
                     *  如果4位表示的不是数字, 转换为16进制ascii码字符
                     */
                    chars[pos++] = (char) (b0 + (b0 < 10 ? 48 : 55));
                    chars[pos++] = (char) (b1 + (b1 < 10 ? 48 : 55));
                }
                chars[pos++] = '\'';
                try {
                    writer.write(chars);
                } catch (IOException ex) {
                    throw new JSONException("writeBytes error.", ex);
                }
                return;
            }
            /** buffer容量不够并且输出器为空,触发扩容 */
            expandCapacity(newcount);
        }

        buf[count++] = 'x';
        buf[count++] = '\'';

        for (int i = 0; i < bytes.length; ++i) {
            byte b = bytes[i];

            int a = b & 0xFF;
            /** 取字节的高四位 */
            int b0 = a >> 4;
            /** 取字节的低四位 */
            int b1 = a & 0xf;

            /** 索引低索引存储字节高位
             *  如果4位表示的数字是 0~9, 转换为ascii的 0~9
             *  如果4位表示的不是数字, 转换为16进制ascii码字符
             */
            buf[count++] = (char) (b0 + (b0 < 10 ? 48 : 55));
            buf[count++] = (char) (b1 + (b1 < 10 ? 48 : 55));
        }
        buf[count++] = '\'';
    }

writeHex 这个序列化方法主要对16进制的自己转换为占用2个ascii码字符,添加单引号和x前缀。

序列化byte字节数组

   public void writeByteArray(byte[] bytes) {
        if (isEnabled(SerializerFeature.WriteClassName.mask)) {
            /** 如果开启序列化特性WriteClassName,直接写16进制字符 */
            writeHex(bytes);
            return;
        }

        int bytesLen = bytes.length;
        final char quote = useSingleQuotes ? '\'' : '"';
        if (bytesLen == 0) {
            String emptyString = useSingleQuotes ? "''" : "\"\"";
            /** 如果字节数组长度为0,输出空白字符 */
            write(emptyString);
            return;
        }

        final char[] CA = IOUtils.CA;

        /** 验证长度是24bit位整数倍 */
        int eLen = (bytesLen / 3) * 3;
        /** base64 编码字符长度
         *
         *  base64 :
         *  第一步,将每三个字节作为一组,一共是24个二进制位。
         *  第二步,将这24个二进制位分为四组,每个组有6个二进制位。
         *  第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
         *  第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。
         *
         *  ref: http://www.ruanyifeng.com/blog/2008/06/base64.html
         */
        int charsLen = ((bytesLen - 1) / 3 + 1) << 2;
        // char[] chars = new char[charsLen];
        int offset = count;
        int newcount = count + charsLen + 2;
        if (newcount > buf.length) {
            if (writer != null) {
                write(quote);

                for (int s = 0; s < eLen;) {
                    /** 三个字节为一组, 扩展为四个字节 */
                    int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);

                    write(CA[(i >>> 18) & 0x3f]);
                    write(CA[(i >>> 12) & 0x3f]);
                    write(CA[(i >>> 6) & 0x3f]);
                    /** 填充00 */
                    write(CA[i & 0x3f]);
                }

                /** 对齐并编码剩余不足3个字节为一组的数据 */
                // Pad and encode last bits if source isn't even 24 bits.
                int left = bytesLen - eLen; // 0 - 2.
                if (left > 0) {

                    /**
                     * a) 1个字节的情况:
                     * 将这1字节8位二进制,每6位分成2组,最后一组除了前面加00,后面加上0000,
                     * 这样得到 两位的Base64编码, 在末尾补上2个"="号
                     *
                     * b) 2个字节的情况:
                     * 将这2字节的一共16个二进制位,每6位分成3组,最后一组除了前面加00,后面也要加00,
                     * 这样得到 3位的Base64编码, 在末尾补上"="号
                     *
                     *
                     * 如果只有1个字节,按照前面规则a)
                     * 第1组是6位,第2组后面4个0, 因此应该左移 10 = 6 + 4
                     *
                     * 如果只有2个字节,按照前面规则b)
                     * 第1个字节左移 10 位 加上 第2个字节左移 2 位补0即可
                     */
                    int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);

                    /** 扩展为四个字节 */
                    write(CA[i >> 12]);
                    write(CA[(i >>> 6) & 0x3f]);
                    write(left == 2 ? CA[i & 0x3f] : '=');
                    write('=');
                }

                write(quote);
                return;
            }
            expandCapacity(newcount);
        }
        count = newcount;
        buf[offset++] = quote;

        // Encode even 24-bits
        for (int s = 0, d = offset; s < eLen;) {
            /** 三个字节为一组, 扩展为四个字节 */
            int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);

            // Encode the int into four chars
            buf[d++] = CA[(i >>> 18) & 0x3f];
            buf[d++] = CA[(i >>> 12) & 0x3f];
            buf[d++] = CA[(i >>> 6) & 0x3f];
            /** 填充00 */
            buf[d++] = CA[i & 0x3f];
        }

        /** 对齐并编码剩余不足3个字节为一组的数据 */
        int left = bytesLen - eLen; // 0 - 2.
        if (left > 0) {
            // Prepare the int
            int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);

            /** 扩展为四个字节 */
            buf[newcount - 5] = CA[i >> 12];
            buf[newcount - 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值