Convert io.Reader or io.ReadCloser to a String in Go

Drain a golang io.Reader or io.ReadCloser into a string with io.ReadAll and string(b), or stream with strings.Builder and io.Copy or bytes.Buffer.ReadFrom; use strings.NewReader when you need a reader from a string.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Convert io.Reader or io.ReadCloser to a String in Go

If you want a golang reader to string flow, you are draining something that implements io.Reader until EOF, then turning the bytes into a string. The same pattern answers golang io.reader to string and io.readcloser to string / golang io.readcloser to string, because io.ReadCloser is still an io.Reader for the Read side. For a golang io reader example, the standard library gives io.ReadAll, io.Copy into strings.Builder, or bytes.Buffer.ReadFrom. People who search for strings.newreader usually need the opposite direction—a golang reader from string—which is strings.NewReader, not a reader-to-string conversion.

Tested with Go 1.24 on Linux.


From io.Reader or io.ReadCloser to string

io.ReadAll then string(bytes) (most direct)

io.ReadAll reads until EOF and returns a []byte and an error. On success, string(b) gives your string. This is the default choice for golang io.reader to string when you want the entire stream.

Run it: you should see This is GoLinuxCloud! printed.

go
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("This is GoLinuxCloud!")
	b, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(b))
}
Output

strings.Builder and io.Copy

strings.Builder implements io.Writer. io.Copy streams from the reader into the builder until EOF, then String() returns the result. Useful when you already pipeline through io.Copy or combine multiple writes.

Run it: same line of output as the ReadAll example.

go
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("This is GoLinuxCloud!")
	var buf strings.Builder
	if _, err := io.Copy(&buf, r); err != nil {
		log.Fatal(err)
	}
	fmt.Println(buf.String())
}
Output

bytes.Buffer and ReadFrom

bytes.Buffer is a growable byte buffer with ReadFrom and String. It is a good fit when you want []byte access as well as string, or when older code already centers on bytes.Buffer.

Run it: same final line as above.

go
package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("This is GoLinuxCloud!")
	var buf bytes.Buffer
	if _, err := buf.ReadFrom(r); err != nil {
		log.Fatal(err)
	}
	fmt.Println(buf.String())
}
Output

io.ReadCloser and Close

For types like HTTP response bodies, the concrete type is often an io.ReadCloser. Reading until EOF with io.ReadAll or io.Copy is unchanged. Call Close() when the documentation says it frees a socket or file descriptor; it does not change how you build the string after the reads succeed.


Reader from a string: strings.NewReader

strings.NewReader returns an io.Reader (and more) that reads from an existing string. That matches golang string reader and golang reader from string intent. It does not allocate a []byte copy of the whole string up front the way some older patterns did; it is read-only and efficient for passing string data into APIs that want a reader.

go
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("peek")
	buf := make([]byte, 2)
	_, err := r.Read(buf)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(buf))
}
Output

You should see pe (the first two bytes).

For turning a byte slice into a reader, see byte slice to io.Reader. For the reverse of this article—reader to raw []byteio.ReadAll already returns []byte; you can also use a buffer as in that post.


io.Writer, io.ReadWriter, and go io reader writer

Queries such as go io reader writer usually point at io.ReadWriter, the interface that combines io.Reader and io.Writer. Types like net.Conn implement both ends. Converting a reader to a string does not require io.Writer unless you choose the io.Copy(dst, src) form, where dst must be a Writerstrings.Builder and bytes.Buffer satisfy that.


Summary

For golang reader to string, read the stream to completion with io.ReadAll and convert with string(b), or stream into strings.Builder via io.Copy, or use bytes.Buffer.ReadFrom then String(). io.ReadCloser uses the same read path; Close is about resources, not string assembly. strings.NewReader is the strings.newreader / golang io.reader from string direction: it wraps a string as a Reader, not the other way around. Prefer io.ReadAll over deprecated ioutil.ReadAll on supported Go versions.


References


Frequently Asked Questions

1. How do I convert a golang io.Reader to a string?

Read the entire stream with io.ReadAll(r), check the error, then use string(b). That is the usual one-liner for in-memory or network bodies when you want the whole payload as text.

2. Is golang io.ReadCloser to string different from io.Reader?

No for reading the body: io.ReadCloser embeds io.Reader, so io.ReadAll works the same. You may still call Close() after reading when the type documents that Close releases resources, but ReadAll stops at EOF and does not require Close for correctness of the string result.

3. What does strings.NewReader do?

strings.NewReader builds an io.Reader that reads from an existing string. It answers golang reader from string or golang io.reader from string searches; it does not convert a reader to a string—that direction uses ReadAll or a Builder.

4. When should I use strings.Builder versus io.ReadAll for reader to string?

Prefer io.ReadAll when you want the whole stream as bytes then convert once. Use strings.Builder with io.Copy when you are already writing to a Builder from multiple writers or want a streaming accumulate without holding a separate []byte first.

5. Where did ioutil.ReadAll go?

Since Go 1.16, ioutil.ReadAll is deprecated in favor of io.ReadAll in the io package. New code should use io.ReadAll.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …