Rust实战学习之base64编码

科技资讯 投稿 35000 0 评论

Rust实战学习之base64编码

编码原理很简单,将原始数据以3字节(24比特)为一组均分成4份,每部分6比特共64种组合,每种组合转换成对应字符,最后拼接起来即可。若最后一组不够3字节则后面用0补齐,转换后补齐多少字节就用几个“=”字符表示。

一、标准输出读取

程序的数据是从标准输入(stdin)中读取的,使用返回实现Read特性(trait)的Stdin结构体,调用Read特性read函数即可从标准输出读取数据,例子如下。

let buf: [u8; 300] = [0; 300];
let size = stdin(.read(&buf.unwrap(;

read使用一个u8类型数组用作从标准输入接收数据的缓存,接收到的字节数以包裹在Result中的usize类型返回,这里简单地使用解包获取字节数。

let mut buf: [u8; 300] = [0; 300];

loop {
    let size = stdin(.read(&mut buf.unwrap(;
    if size == 0 {
        break;
    }
    // Output the buffer, and assume that buffer is utf-8 string.
    print!("{}", String::from_utf8(buf.to_vec(.unwrap(;
}

二、IO抽象模型

与Java的InputStream和OutputStream一样,rust也有IO抽象模型,那就是Read和Write特性。

使用时无需知道其实现是标准输入输出、文件还是网络,例如可以实现一个输入源自动匹配函数,当指定路径的文件不存在就读取标准输入,反之就从文件中读取内容。

fn main( {
    let mut buf: [u8; 300] = [0; 300];

    loop {
        let size = input("./input".read(&mut buf.unwrap(;
        if size == 0 {
            break;
        }
        print!("{}", String::from_utf8(buf.to_vec(.unwrap(
    }
}

fn input(path: &'static str -> Box<dyn Read> {
    if !Path::new(path.exists( {
        return Box::new(stdin(;
    }
    Box::new(File::open(path.unwrap(
}

三、数组

rust数组是定长的,因此声明时必须明确长度及类型以便分配内存,长度和类型可以自动推断也可指定。

let arr: [i32; 4]; // 1. Specify type and length, the format is [Type; length].
let arr = [0, 4]; // 2. Infer type automatically.
let arr = [0, 0, 0, 0]; // 3. Infer type and length.

与其他多数语言一样也是使用下标访问元素,超出范围会直接panic。

let mut arr = [0, 0, 0, 0];
print!("{}", arr[0]; // Output is 0.
arr[0] = 1;
print!("{}", arr[0]; // Output is 1.
arr[4] = 4; // Panic here.

四、字符串

rust的字符串有str和String两种:

  1. str是原始类型,其实现是一种切片(Slice)类型且不可变,由于切片类型没有所有权,因此只能是以引用方式&str出现;

  2. String有所有权且可变,其使用的是堆内存,因此开销会比str大。

let a = String.from("a";
let b = "b";
let _ = a + b;
// Can not use variable "a" here, its ownership has been moved

注意这里作为左值的a变量在运算后不能在被使用,因为其所有权已经被移动。

五、附录

base64编码实现完整代码如下:

use std::io::{stdin, Read};

fn main( {
    let mut buf: [u8; 300] = [0; 300];
    loop {
        let size = stdin(.read(&mut buf.unwrap(;
        if size == 0 {
            break;
        }
        print!("{}", String::from_utf8(buf.to_vec(.unwrap(;
        print!("{}", encode(&buf, size;
    }
}

fn encode(bytes: &[u8], size: usize -> String {
    let mut buf = String::new(;
    let i = 0;
    for mut i in 0..(size / 3 {
        i = i * 3;
        let f = bytes[i];
        let s = bytes[i + 1];
        let t = bytes[i + 2];

        buf.push_str(&cvt((f & 0xfc >> 2;
        buf.push_str(&cvt((f & 0x03 << 4 | ((s & 0xf0 >> 4;
        buf.push_str(&cvt((s & 0x0f << 2 | ((t & 0xc0 >> 6;
        buf.push_str(&cvt(t & 0x3f;
    }

    let mut i = (i + 1 * 3;
    i = if size < i { 0 } else { i };
    let remain = size - i;
    if remain == 1 {
        let f = bytes[i];
        buf.push_str(&cvt((f & 0xfc >> 2;
        buf.push_str(&cvt((f & 0x03 << 4 | 0;
        buf.push_str("==";
    } else if remain == 2 {
        let f = bytes[i];
        let s = bytes[i + 1];
        buf.push_str(&cvt((f & 0xfc >> 2;
        buf.push_str(&cvt((f & 0x03 << 4 | ((s & 0xf0 >> 4;
        buf.push_str(&cvt((s & 0x0f << 2 | 0;
        buf.push_str("=";
    }
    buf
}

const BASE64_TABLE: [char; 64] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
    'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
    '5', '6', '7', '8', '9', '+', '/',
];

fn cvt(i: u8 -> String {
    BASE64_TABLE.get(i as usize.unwrap(.to_string(
}

编程笔记 » Rust实战学习之base64编码

赞同 (34) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽