ฉันมีio.ReadCloser
วัตถุ (จากhttp.Response
วัตถุ)
วิธีใดที่มีประสิทธิภาพที่สุดในการแปลงสตรีมทั้งหมดเป็นstring
วัตถุ
ฉันมีio.ReadCloser
วัตถุ (จากhttp.Response
วัตถุ)
วิธีใดที่มีประสิทธิภาพที่สุดในการแปลงสตรีมทั้งหมดเป็นstring
วัตถุ
คำตอบ:
แก้ไข:
ตั้งแต่ 1.10 มีสตริง Builder อยู่ ตัวอย่าง:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
ข้อมูลที่ล้าสมัยด้านล่าง
คำตอบสั้น ๆ คือมันจะไม่มีประสิทธิภาพเนื่องจากการแปลงเป็นสตริงต้องทำสำเนาไบต์อาร์เรย์ทั้งหมด นี่คือวิธีที่เหมาะสม (ไม่มีประสิทธิภาพ) ในการทำสิ่งที่คุณต้องการ:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
สำเนานี้ทำขึ้นเพื่อเป็นกลไกในการป้องกัน สตริงไม่เปลี่ยนรูป หากคุณสามารถแปลง [] ไบต์เป็นสตริงคุณสามารถเปลี่ยนเนื้อหาของสตริงได้ อย่างไรก็ตาม go ช่วยให้คุณปิดใช้งานกลไกความปลอดภัยโดยใช้แพ็คเกจที่ไม่ปลอดภัย ใช้แพ็กเกจที่ไม่ปลอดภัยโดยยอมรับความเสี่ยงเอง หวังว่าชื่อเพียงอย่างเดียวเป็นคำเตือนที่ดีพอ นี่คือวิธีที่ฉันจะทำโดยใช้ที่ไม่ปลอดภัย:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
ไปเลยตอนนี้คุณได้แปลงอาร์เรย์ไบต์ของคุณเป็นสตริงอย่างมีประสิทธิภาพแล้ว จริงๆแล้วทั้งหมดนี้หลอกให้ระบบพิมพ์เรียกมันว่าสตริง มีข้อแม้สองสามประการสำหรับวิธีนี้:
คำแนะนำของฉันคือยึดตามวิธีการอย่างเป็นทางการ การทำสำเนาไม่ได้ว่าราคาแพงและไม่คุ้มค่าความชั่วร้ายของที่ไม่ปลอดภัย หากสตริงมีขนาดใหญ่เกินไปที่จะทำสำเนาคุณไม่ควรทำให้เป็นสตริง
strings.Builder
ทำสิ่งนี้ได้อย่างมีประสิทธิภาพโดยตรวจสอบให้แน่ใจว่าสิ่งที่อยู่ข้างใต้[]byte
จะไม่รั่วไหลและแปลงเป็นstring
โดยไม่มีสำเนาในลักษณะที่จะได้รับการสนับสนุนต่อไป สิ่งนี้ไม่มีในปี 2012 วิธีแก้ปัญหาของ @dimchansky ด้านล่างนี้เป็นวิธีที่ถูกต้องตั้งแต่ Go 1.10 โปรดพิจารณาแก้ไข!
คำตอบยังไม่ได้ระบุส่วน "สตรีมทั้งหมด" ของคำถาม ioutil.ReadAll
ผมคิดว่าวิธีที่ดีที่จะทำเช่นนี้คือ ด้วยio.ReaderCloser
ชื่อของคุณrc
ฉันจะเขียนว่า
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()
ยังอ่านสตรีมทั้งหมดได้ถึง EOF
ioutil.ReadAll()
และมันก็ตัด'sbytes.Buffer
ReadFrom
และวิธีการบัฟเฟอร์String()
นั้นเป็นการพันรอบการแคสต์ไปstring
- ดังนั้นทั้งสองวิธีจึงเหมือนกันจริง ๆ !
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
วิธีที่มีประสิทธิภาพที่สุดคือการใช้[]byte
แทนstring
เสมอ
ในกรณีที่คุณต้องพิมพ์ข้อมูลที่ได้รับจากio.ReadCloser
การfmt
แพคเกจสามารถจัดการ[]byte
แต่มันก็ไม่ได้มีประสิทธิภาพเพราะfmt
การดำเนินงานภายในจะแปลงไป[]byte
string
เพื่อหลีกเลี่ยงการแปลงนี้คุณสามารถใช้อินเตอร์เฟซสำหรับประเภทเช่นfmt.Formatter
type ByteSlice []byte
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()
ผมชอบbytes.Buffer struct ฉันเห็นว่ามันมีวิธีReadFromและString ฉันเคยใช้กับ [] ไบต์ แต่ไม่ใช่ io.Reader