有趣的 Kotlin 0x14:Base64编码

news2024/11/15 9:43:29

前言

Concise. Cross‑platform. Fun.

Kotlin 来到 1.8.20 版本, 又给开发者带来了很多更新, 今天关注下标准库中新增的 Base64 相关内容.

原理

Base64编码是一种将二进制数据转换为可打印ASCII字符的编码方式。它使用64个不同的字符(通常是A-Z、a-z、0-9和两个额外的字符 “+” 和 “/”)来表示二进制数据中的6位,从而将8位的二进制数据转换为6位的ASCII字符。

Base64编码的原理如下:

  1. 将输入的二进制数据分割成每6位一组的数据块。
  2. 每个6位的数据块表示一个整数值,范围从0到63(因为2^6=64)。
  3. 将这个整数值映射到Base64字符集中的对应字符。例如,整数值为0时对应字符集中的第一个字符(通常是"A"),整数值为1时对应字符集中的第二个字符(通常是"B"),以此类推。
  4. 对于不足6位的数据块,可以进行填充,通常使用字符 “=” 来填充。
  5. 将所有的Base64字符连接在一起,形成最终的Base64编码字符串。

解码时,按照相反的过程进行:

  1. 将Base64编码的字符串按照字符集映射关系,还原成对应的整数值。
  2. 将整数值转换为6位二进制数据。
  3. 将多个6位二进制数据组合成完整的二进制数据。
  4. 最后,根据具体的编码前的二进制数据类型,将二进制数据转换为相应的数据类型,如字符串、图片、音频等。

Base64编码常用于将二进制数据传输或储存于文本协议中,例如在电子邮件中传输二进制附件、在URL中传递二进制参数、在JSON或XML等文本格式中嵌入二进制数据等场景。

常见三种编码方案

Base64编码通常有几种不同的编码方案,也称为编码表或字符集。这些编码方案包括:

  1. 标准Base64:也称为RFC 4648中定义的Base64编码,它使用64个字符作为编码表,包括大小写字母(A-Z, a-z)、数字(0-9)以及两个特殊字符(+和/)。此外,还可能包含一个填充字符(=),用于将编码结果的长度补齐为4的倍数。

                          Table 1: The Base 64 Alphabet
    
         Value Encoding  Value Encoding  Value Encoding  Value Encoding
             0 A            17 R            34 i            51 z
             1 B            18 S            35 j            52 0
             2 C            19 T            36 k            53 1
             3 D            20 U            37 l            54 2
             4 E            21 V            38 m            55 3
             5 F            22 W            39 n            56 4
             6 G            23 X            40 o            57 5
             7 H            24 Y            41 p            58 6
             8 I            25 Z            42 q            59 7
             9 J            26 a            43 r            60 8
            10 K            27 b            44 s            61 9
            11 L            28 c            45 t            62 +
            12 M            29 d            46 u            63 /
            13 N            30 e            47 v
            14 O            31 f            48 w         (pad) =
            15 P            32 g            49 x
            16 Q            33 h            50 y
    
  2. URL安全Base64:这种编码方案在标准Base64的基础上进行了修改,用于在URL和文件名中传输数据,避免了一些特殊字符在URL中可能引起的问题。URL安全Base64使用大小写字母(A-Z, a-z)、数字(0-9)以及两个特殊字符(-和_)作为编码表,不使用+和/作为编码字符,也不使用=作为填充字符。

    Table 2: The "URL and Filename safe" Base 64 Alphabet
    
         Value Encoding  Value Encoding  Value Encoding  Value Encoding
             0 A            17 R            34 i            51 z
             1 B            18 S            35 j            52 0
             2 C            19 T            36 k            53 1
             3 D            20 U            37 l            54 2
             4 E            21 V            38 m            55 3
             5 F            22 W            39 n            56 4
             6 G            23 X            40 o            57 5
             7 H            24 Y            41 p            58 6
             8 I            25 Z            42 q            59 7
             9 J            26 a            43 r            60 8
            10 K            27 b            44 s            61 9
            11 L            28 c            45 t            62 - (minus)
            12 M            29 d            46 u            63 _
            13 N            30 e            47 v           (underline)
            14 O            31 f            48 w
            15 P            32 g            49 x
            16 Q            33 h            50 y         (pad) =
    
  3. MIME Base64:这种编码方案通常用于在邮件中传输二进制数据。MIME Base64与标准Base64编码方式相同,但可能会在编码结果的行末添加换行符,以适应邮件传输的需求。

这些不同的Base64编码方案在编码表和字符集上有所不同,但基本的编码原理和解码方式都是相同的。在使用Base64编码时,需要根据具体的应用场景和需求选择合适的编码方案。例如,在传输数据时,如果数据将用于URL或文件名中,应使用URL安全Base64编码;如果数据将用于电子邮件中,应使用MIME Base64编码。

Kotlin 手写

根据规则先自行实现 Base64 编解码.

编码

val BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray()
// 以参数为"Hello, World!"为示例
fun base64encode(source: String): String {
    val originalBytes = source.toByteArray()
    // originalBytes = [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
    val binaryStrings = originalBytes.map { byte -> byte.toString(2).padStart(8, '0') }
    // binaryStrings = ["01001000", "01100101", "01101100", "01101100", "01101111", "00101100", "00100000", "01010111", "01101111", "01110010", "01101100", "01100100", "00100001"]
    val binaryString = binaryStrings.joinToString("")
    // binaryString = "0100100001100101011011000110110001101100011011110010110000100000010101110110111101110010011011000110110001100100"
    val chunks = binaryString.chunked(6) { chunk -> chunk.padEnd(6, '0') }
    // chunks = ["010010", "000110", "010110", "110011", "000110", "110000", "110111", "001011", "000010", "101110", "110111", "001110", "010011", "011000", "110110", "001100"]
    val encodedChars = chunks.map { chunk -> chunk.toString().toInt(2) }
        .map { index -> BASE64_CHARS[index] }
        .toCharArray()
    // encodedChars = ['S', 'G', 'V', 's', 'b', 'i', 'B', '0', 'I', 'F', 'c', 'b', 'G', '9', 'v', '4', 'E', 'h', 'd', 'A']
    return addPadding(String(encodedChars))
    // encodedString = "SGVsbG8sIFdvcmxkIQ=="
}

// 补成4的倍数
fun addPadding(input: String): String {
    val remainder = input.length % 4
    return if (remainder == 0) {
        input
    } else {
        val padding = "=".repeat(4 - remainder)
        input + padding
    }
}

解码

fun base64decode(encodedString: String): String {
    val encodedChars = encodedString.toCharArray()
    val chunks = encodedChars.map { char -> BASE64_CHARS.indexOf(char) }
        .filter { index -> index != -1 }
        .joinToString("") { index -> index.toString(2).padStart(6, '0') }
        .chunked(8).filter { it.length == 8 }
    val binaryBytes = chunks.map { chunk ->
        chunk.toInt(2).toByte()
    }.toByteArray()
    return String(binaryBytes)
}

Kotlin 1.8.20 标准库

编码

val foBytes = "fo".map { it.code.toByte() }.toByteArray()
println(Base64.Default.encode(foBytes)) // "Zm8="
println(Base64.encode(foBytes)) // "Zm8="

val foobarBytes = "foobar".map { it.code.toByte() }.toByteArray()
println(Base64.UrlSafe.encode(foobarBytes)) // "Zm9vYmFy"

解码

println(String(Base64.Default.decode("Zm8=")))// foBytes
println(String(Base64.decode("Zm8=")))
println(String(Base64.UrlSafe.decode("Zm9vYmFy"))) // foobarBytes

后记

https://www.rfc-editor.org/rfc/rfc4648

除了 Base64 , 还有 Base32、Base16 等各种 Base-N 编码规则, 原理类似可举一反三自行贯通. 看官方文档的时候, 还顺便帮他们改了个小错误.
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/453402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学会SpringBoot的第一天(超详细)

🙈作者简介:练习时长两年半的Java up主 🙉个人主页:老茶icon 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,计…

d2l Transformer

终于到变形金刚了,他的主要特征在于多头自注意力的使用,以及摒弃了rnn的操作。 目录 1.原理 2.多头注意力 3.逐位前馈网络FFN 4.层归一化 5.残差连接 6.Encoder 7.Decoder 8.训练 9.预测 1.原理 主要贡献:1.纯使用attention的Enco…

JavaFX与Liberica JDK,搭建,运行,打包,放弃Eclipse

1、官网 JavaFX中文官方网站、Oracle官方文档 2、教程 JavaFX中文基础教程视频合集 JavaFX实战教程 3、VSCode/Eclipse VSCode(写HelloWorld用)、VSCode的Java扩展 Eclipse,跳至第9段 4、Liberica JDK安装 Liberica JDK官网下载 依次选择,All ve…

压力测试防踩坑指南,压测中要注意的那些事儿

对于一些高频访问接口,压力测试必不可少,本文主要叙述了自己在压测过程中遇到的问题,在此分享,希望能帮助大家避免踩坑,提高效率。 1.pod数量 现象:服务器资源充足,tps上不去,检查发…

OneData 共享同一套数据技术和资产

一、什么是 OneData 体系? 官方:阿里云OneData数据中台解决方案基于大数据存储和计算平台为载体,以OneModel统一数据构建及管理方法论为主干,OneID核心商业要素资产化为核心,实现全域链接、标签萃取、立体画像,以数据…

ASEMI代理ADI亚德诺ADAU1701JSTZ-RL车规级芯片

编辑-Z ADAU1701JSTZ-RL芯片参数: 型号:ADAU1701JSTZ-RL 模拟电源电压:3.3 V 数字电源电压:1.8 V 输入/输出电压:3.3 V 环境温度:25 C 主时钟输入:12.288 MHz 满刻度模拟输入&#xff1…

彻底掌握FreeRTOS中的务通知(Task Notifications)

​在之前的文章中已经讲解了很多种用于任务件通信的机制,包括队列、事件组和各种不同类型的信号量。使用这些机制都需要创建一个通信对象。 事件和数据不会直接发送到接收任务或接收ISR,而是发送到通信对象(也就是发送到队列、事件组、信号量…

2023软考中级《软件设计师》(备考冲刺版) | 操作系统

目录 1.操作体统相关概念 1.1 操作系统的功能 1.2 特殊的操作系统 2.进程管理 2.1进程的概念 2.1.1 线程的概念 2.1.2 进程的状态 2.2 进程调度 2.2.1 PV操作的概念 2.2.2 信号量和PV操作 2.2.3 前趋图与PV操作 3.存储管理 3.1 页式存储 3.2 段式存储 3.3 段页式…

智慧安防小区管控系统解决方案(ppt可编辑)

本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除 智慧安防小区-建设思路及目标 智慧安防小区管控子系统是,按照“数据向上集中、服务向下延伸”的思路,对相关要素进行重点采集,实现社区态势…

【JAVAEE】网络原理之网络通信基础

目录 1. 💋IP地址 1.1 🍟IP地址的格式 1.2 🎁特殊IP地址 2. ✨端口号 2.1 🎃端口号的格式 3. 😘网络协议 3.1 🎨为什么需要网络协议? 3.2 💛网络协议的概念与组成 3.3 &am…

答题积分小程序云开发实战-界面交互篇:首页页面布局样式与逻辑交互开发

微信小程序云开发实战-答题积分赛小程序 界面交互篇:首页页面布局样式与逻辑交互开发 首页效果图 布局思路 5行布局,即5个块级元素,轮播图、通告栏、个人信息、功能区、版权。

将服务器select模型设置为非阻塞,处理更多业务

timeval结构体在头文件为sys/time.h中,定义如下: struct timeval {long tv_sec; /* seconds */long tv_usec; /* and microseconds */ }; 其中tv_sec是秒,tv_usec是微秒(microsecond )&#xff0…

[单片机框架][bsp层][cx32l003][bsp_tim] Baes TIM 基础定时器配置和使用

文章目录 一、基础定时器介绍二、功能描述(1) Buzzer 功能 三、示例代码(PWM) 一、基础定时器介绍 基础定时器 Base Timer 包含两个定时器 TIM10/11。TIM10/11 功能完全相同。TIM10/11 是同步定时/计数器,可以作为 16/32 位自动重装载功能的定时/计数器&#xff0c…

VS2022配置GDAL

GDAL(Geospatial Data Abstraction Library)是一个用于处理地理空间数据的开源库。它提供了一组功能丰富的API,用于读取、写入、转换和处理各种地理空间数据格式,包括栅格数据(如卫星图像、数字高程模型)和…

Jupyter创建Anaconda多个虚拟环境教程

这里写目录标题 1.1界面化创建虚拟环境1.2命令行创建虚拟环境2.查看是否创建成功3.激活虚拟环境pylessonppt4.更改工作目录5.删除6.查看是否删除成功 1.1界面化创建虚拟环境 1.2命令行创建虚拟环境 conda create -n myenv——name pythonx.xmyenv-name:自己定义的环境名称 pyt…

fastjson反序列化漏洞复现

fastjson反序列化漏洞复现 一.影响版本: Fastjson<1.2.24二.实验过程图三.实验步骤四&#xff0c;实验结果以及参考链接 一.影响版本: Fastjson<1.2.24 二.实验过程图 (踩坑) rmijndi环境&#xff1a;java.sql.SQLException: JdbcRowSet (连接) JNDI 无法连接 2、ldapjn…

上海无纺布制造商【盈兹】申请纳斯达克IPO上市,募资1100万美元

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;来自上海的无纺布制造商【盈兹】&#xff0c;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码为&#xff08;ETZ&#…

Invalid bound statement (not found)的原因以及解决方法

相信我们在学习Mybatis的时候都出现过 Invalid bound statement (not found) 这个错误&#xff0c;一般由以下几种可能导致这个错误 一&#xff1a;mapper方法名 和 mapper.xml id名不对应 例如&#xff1a; mapper&#xff1a; 对应的mapper.xml 这里建议小伙伴们下载一个插…

Linux中的YUM源仓库和NFS文件共享服务

这里写目录标题 一 、YUM仓库源的介绍和相关信息1.1yum相关介绍1.2 Linux系统各家厂商用的安装源1.3 yum下载方式 二 、 yum 仓库源的三种搭建2.1yum 配置本地源2.2创建ftp源2.3 配置http源2.4 配置yum在线源 三 、NFS的简介3.1 什么是NFS3.2 linux中要使用NFS需要下载的软件包…

User Diverse Preference Modeling by Multimodal Attentive Metric Learning

BACKGROUND 现有模型通常采用一个固定向量去表示用户偏好&#xff0c;在假设——特征向量每一个维度都代表了用户的一种特性或者一个方面&#xff0c;这种方式似乎不妥&#xff0c;因为用户对于不同物品的偏好是不一样的&#xff0c;例如因演员喜欢一部电影&#xff0c;而因特…