ฉันมี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.Formattertype 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