Question:
Is there a way to take an io.Reader that contains binary data, and read it out base64 encoded.
I see in encoding/base64 there is
1 2 |
func NewDecoder(enc *Encoding, r io.Reader) io.Reader |
but that assumes the io.Reader data is base64 and returns an io.Reader to decode it to binary.
and
1 2 |
func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser |
which returns a io.Writer to encode binary to base64 but I’m need to use the go-aws-sdk s3manage Uploader, which takes an io.Reader interface.
1 2 3 4 5 6 7 |
uploader := s3manager.NewUploaderWithClient(svc) _, err := uploader.Upload(&s3manager.UploadInput{ Bucket: aws.String(bucket), Key: aws.String(key), Body: input, }) |
input needs implement the io.Reader interface
The data is large, so I don’t want to read the input fully into memory before doing the encoding
Answer:
The concept of a Pipe is used to change Readers into Writers and vice-versa.
Using an io.Pipe
, you can copy the source io.Reader
into the encoder, and pass the io.PipeReader
as the body to be uploaded.
The error handling is a little unusual if you want to pass it through, but it’s possible using the CloseWithError
method. Make sure you also note the correct order to close the pipe and encoder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
source := strings.NewReader("Hello, World!") pr, pw := io.Pipe() encoder := base64.NewEncoder(base64.StdEncoding, pw) go func() { _, err := io.Copy(encoder, source) encoder.Close() if err != nil { pw.CloseWithError(err) } else { pw.Close() } }() |