首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有限行长的base64编码(按RFC2045计算)

有限行长的base64编码(按RFC2045计算)
EN

Stack Overflow用户
提问于 2019-09-04 15:45:29
回答 1查看 1.2K关注 0票数 8

RFC2045节6.8规定base64输出的最大编码行长度应为76个字符或以下。

正如这里所看到的,Golang流编写器base64.NewEncoder没有任何行拆分选项。

代码语言:javascript
复制
package main

import (
    "encoding/base64"
    "io"
    "os"
    "strings"
)


// 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"
    rdr := strings.NewReader(data)
    wrt := base64.NewEncoder(base64.StdEncoding, os.Stdout)
    io.Copy(wrt, rdr)
}

输出是

代码语言:javascript
复制
SXQgaXMgb25seSB0aGUgaGFpcnMgb24gYSBnb29zZWJlcnJ5IHRoYXQgcHJldmVudCBpdCBmcm9tIGJlaW5nIGEgZ3JhcGUhIEl0IGlzIG9ubHkgdGhlIGhhaXJzIG9uIGEgZ29vc2ViZXJyeSB0aGF0IHByZXZlbnQgaXQgZnJvbSBiZWluZyBhIGdyYXBl

是否有一个基于流的解决方案来分割行?MIME库只提供基于字符串的编码选项。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-04 18:49:58

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

代码语言:javascript
复制
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))
    }
}

..。欢迎评论/改进。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57791873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档