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.Builder
thực hiện điều này một cách hiệu quả bằng cách đảm bảo cơ sở []byte
không bao giờ bị rò rỉ và chuyển đổi sang string
khô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.ReaderCloser
tê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 []byte
thay vì string
.
Trong trường hợp bạn cần in dữ liệu nhận được từ io.ReadCloser
, fmt
gói có thể xử lý []byte
, nhưng nó không hiệu quả vì việc fmt
triển khai sẽ chuyển đổi nội bộ []byte
sang string
. Để tránh chuyển đổi này, bạn có thể triển khai fmt.Formatter
giao diện cho một loại như type ByteSlice []byte
.
[]byte
sang string
khá 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 string
khi chuyển đổi []byte
sang 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 []byte
sẽ đượ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.