为了账号安全,请及时绑定邮箱和手机立即绑定

根据 RFC2045 限制行长度的 Base64 编码

根据 RFC2045 限制行长度的 Base64 编码

Go
侃侃尔雅 2023-07-17 17:45:46
RFC2045 第 6.8 节规定 Base64 输出的最大编码行长度应为 76 个字符或更少。Golang 流编写器base64.NewEncoder没有任何行分割选项,如此处所示。package mainimport (    "encoding/base64"    "io"    "os"    "strings")// See https://www.ietf.org/rfc/rfc2045.txt, section 6.8 for notes on maximum line length of 76 charactersfunc main() {    data := "It is only the hairs on a gooseberry that prevent it from being a grape! This is long enough to need a line split"    rdr := strings.NewReader(data)    wrt := base64.NewEncoder(base64.StdEncoding, os.Stdout)    io.Copy(wrt, rdr)}输出是SXQgaXMgb25seSB0aGUgaGFpcnMgb24gYSBnb29zZWJlcnJ5IHRoYXQgcHJldmVudCBpdCBmcm9tIGJlaW5nIGEgZ3JhcGUhIEl0IGlzIG9ubHkgdGhlIGhhaXJzIG9uIGEgZ29vc2ViZXJyeSB0aGF0IHByZXZlbnQgaXQgZnJvbSBiZWluZyBhIGdyYXBl是否有基于流的分割线解决方案?MIME库仅提供基于字符串的编码选项。
查看完整描述

1 回答

?
梦里花落0921

TA贡献1772条经验 获得超6个赞

这是我尝试创建一个简单的Writer. 它考虑到不同数量的输入数据,具有可配置的块长度和分隔符序列。它使用字节片写入块,这有望提高效率。


package main


import (

    "encoding/base64"

    "io"

    "os"

    "strings"

)


func min(a, b int) int {

    if a < b {

        return a

    }

    return b

}


type linesplitter struct {

    len   int

    count int

    sep   []byte

    w     io.Writer

}


// NewWriter that splits input every len bytes with a sep byte sequence, outputting to writer w

func (ls *linesplitter) NewWriter(len int, sep []byte, w io.Writer) io.WriteCloser {

    return &linesplitter{len: len, count: 0, sep: sep, w: w}

}


// Split a line in to ls.len chunks with separator

func (ls *linesplitter) Write(in []byte) (n int, err error) {

    writtenThisCall := 0

    readPos := 0

    // Leading chunk size is limited by: how much input there is; defined split length; and

    // any residual from last time

    chunkSize := min(len(in), ls.len-ls.count)

    // Pass on chunk(s)

    for {

        ls.w.Write(in[readPos:(readPos + chunkSize)])

        readPos += chunkSize // Skip forward ready for next chunk

        ls.count += chunkSize

        writtenThisCall += chunkSize


        // if we have completed a chunk, emit a separator

        if ls.count >= ls.len {

            ls.w.Write(ls.sep)

            writtenThisCall += len(ls.sep)

            ls.count = 0

        }

        inToGo := len(in) - readPos

        if inToGo <= 0 {

            break // reached end of input data

        }

        // Determine size of the NEXT chunk

        chunkSize = min(inToGo, ls.len)

    }

    return writtenThisCall, nil

}


func (ls *linesplitter) Close() (err error) {

    return nil

}


// See https://www.ietf.org/rfc/rfc2045.txt, section 6.8 for notes on maximum line length of 76 characters

func main() {

    data := "It is only the hairs on a gooseberry that prevent it from being a grape! This is long enough to need a line split"

    shortData := "hello there"


    var ls linesplitter

    lsWriter := ls.NewWriter(76, []byte("\r\n"), os.Stdout)

    wrt := base64.NewEncoder(base64.StdEncoding, lsWriter)


    for i := 0; i < 10; i++ {

        io.Copy(wrt, strings.NewReader(shortData))

        io.Copy(wrt, strings.NewReader(data))

        io.Copy(wrt, strings.NewReader(shortData))

    }

}

...欢迎提出意见/改进。


查看完整回答
反对 回复 2023-07-17
  • 1 回答
  • 0 关注
  • 211 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信