Câu trả lời:
BIÊN TẬP:
Kể từ 1.10, chuỗi.Builder tồn tại. Thí dụ:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
THÔNG TIN BÊN NGOÀI DƯỚI ĐÂY
Câu trả lời ngắn gọn là nó sẽ không hiệu quả vì chuyển đổi thành một chuỗi đòi hỏi phải thực hiện một bản sao hoàn chỉnh của mảng byte. Đây là cách thích hợp (không hiệu quả) để làm những gì bạn muốn:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
Bản sao này được thực hiện như một cơ chế bảo vệ. Dây là bất biến. Nếu bạn có thể chuyển đổi một [] byte thành một chuỗi, bạn có thể thay đổi nội dung của chuỗi. Tuy nhiên, go cho phép bạn vô hiệu hóa các cơ chế an toàn loại bằng cách sử dụng gói không an toàn. Sử dụng gói không an toàn có nguy cơ của riêng bạn. Hy vọng rằng tên một mình là một cảnh báo đủ tốt. Đây là cách tôi sẽ làm nó bằng cách sử dụng không an toàn:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Ở đây chúng tôi đi, bây giờ bạn đã chuyển đổi hiệu quả mảng byte của mình thành một chuỗi. Thực sự, tất cả những điều này là lừa hệ thống loại gọi nó là một chuỗi. Có một vài lưu ý cho phương pháp này:
Lời khuyên của tôi là bám vào phương pháp chính thức. Làm một bản sao không phải là đắt tiền và nó không có giá trị tệ nạn không an toàn. Nếu chuỗi quá lớn để tạo một bản sao, bạn không nên biến nó thành một chuỗi.
strings.Builderthực hiện điều này một cách hiệu quả bằng cách đảm bảo cơ sở []bytekhông bao giờ bị rò rỉ và chuyển đổi sang stringkhông có bản sao theo cách sẽ được hỗ trợ trong tương lai. Điều này đã không tồn tại vào năm 2012. Giải pháp của @ dimchansky dưới đây là giải pháp chính xác kể từ Go 1.10. Vui lòng xem xét một chỉnh sửa!
Các câu trả lời cho đến nay vẫn chưa giải quyết được phần "toàn bộ luồng" của câu hỏi. Tôi nghĩ rằng cách tốt để làm điều này là ioutil.ReadAll. Với io.ReaderClosertên của bạn rc, tôi sẽ viết,
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()cũng đọc toàn bộ luồng lên tới EOF.
ioutil.ReadAll()và nó chỉ đơn giản là kết thúc tốt đẹp một bytes.Buffer's ReadFrom. Và String()phương pháp của bộ đệm là một cách đơn giản để thực hiện string- vì vậy hai cách tiếp cận thực tế giống nhau!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
Cách hiệu quả nhất sẽ là luôn luôn sử dụng []bytethay vì string.
Trong trường hợp bạn cần in dữ liệu nhận được từ io.ReadCloser, fmtgói có thể xử lý []byte, nhưng nó không hiệu quả vì việc fmttriển khai sẽ chuyển đổi nội bộ []bytesang string. Để tránh chuyển đổi này, bạn có thể triển khai fmt.Formattergiao diện cho một loại như type ByteSlice []byte.
[]bytesang stringkhá nhanh, nhưng câu hỏi đặt ra là "cách hiệu quả nhất". Hiện tại, thời gian chạy Go sẽ luôn phân bổ mới stringkhi chuyển đổi []bytesang string. Lý do cho điều này là trình biên dịch không biết cách xác định liệu []bytesẽ được sửa đổi sau khi chuyển đổi hay không. Có một số chỗ để tối ưu hóa trình biên dịch ở đây.
func copyToString(r io.Reader) (res string, err error) {
var sb strings.Builder
if _, err = io.Copy(&sb, r); err == nil {
res = sb.String()
}
return
}
var b bytes.Buffer
b.ReadFrom(r)
// b.String()
Tôi thích cấu trúc byte.Buffer . Tôi thấy nó có các phương thức ReadFrom và String . Tôi đã sử dụng nó với byte [] nhưng không phải là io.Reader.