วิธีการแปลง InputStream เป็น String ใน Scala


111

ฉันมีฟังก์ชันที่มีประโยชน์ซึ่งฉันเคยใช้ใน Java สำหรับการแปลง InputStream เป็น String นี่คือคำแปลโดยตรงสำหรับ Scala:

  def inputStreamToString(is: InputStream) = {
    val rd: BufferedReader = new BufferedReader(new InputStreamReader(is, "UTF-8")) 
    val builder = new StringBuilder()    
    try {
      var line = rd.readLine 
      while (line != null) { 
        builder.append(line + "\n")
        line = rd.readLine
      }
    } finally {
      rd.close
    }
    builder.toString
  }

มีวิธีสำนวนในการทำสิ่งนี้ในสกาล่าหรือไม่?

คำตอบ:


197

สำหรับ Scala> = 2.11

scala.io.Source.fromInputStream(is).mkString

สำหรับ Scala <2.11:

scala.io.Source.fromInputStream(is).getLines().mkString("\n")

ทำในสิ่งเดียวกัน ไม่แน่ใจว่าทำไมคุณถึงต้องการได้เส้นแล้วกาวกลับเข้าด้วยกัน หากคุณสามารถสมมติว่าไม่มีการบล็อกของสตรีมคุณสามารถใช้.availableอ่านข้อมูลทั้งหมดในอาร์เรย์ไบต์และสร้างสตริงจากสิ่งนั้นโดยตรง


2
เหตุผลหนึ่งที่เป็นไปได้ที่ฉันเคยใช้คือการทำให้การสิ้นสุดบรรทัดเป็นปกติในระบบปฏิบัติการต่างๆ
Kevin Wright

คำตอบของ Raam นั้นยอดเยี่ยมเช่นกัน (และกระชับกว่าเล็กน้อย) แต่ทำเครื่องหมายว่า Rex เป็นคำตอบเพราะมันเหมือนกับตัวอย่างโดยเฉพาะ การติดเส้นกลับเข้าด้วยกันเป็นเรื่องเฉพาะบางกรณี แต่คุณเตือนฉันว่าฉันใช้รหัสนี้ในสถานที่ที่ไม่เหมาะสมที่จะทำเช่นนั้น
bballant

วิธีแก้ปัญหาไม่ปลอดภัยมากเนื่องจากใช้ getLines (); จะเกิดอะไรขึ้นถ้าสตรีมอินพุตไม่มีอักขระ "บรรทัดใหม่" จากนั้นสิ่งทั้งหมดก็ปิดกั้น
Paul Sabou

ค่อนข้างเป็นทางออกที่ไม่ดี จะเกิดอะไรขึ้นถ้าอินพุตสตรีมมีการสิ้นสุดบรรทัด DOS (\ r \ n) สิ่งเหล่านี้จะถูกลบออกโดยวิธีนี้ นอกจากนี้แม้ว่า mkString จะใช้บัฟเฟอร์ แต่การอ่านบล็อคอักขระจะเร็วกว่า
Dibbeke

1
@RexKerr คุณช่วยชี้ให้เห็น "ข้อบกพร่องด้านประสิทธิภาพ" ที่คุณพูดถึงในคำตอบของคุณได้ไหม ฉันทดสอบทั้งสองเวอร์ชันด้วยการทดสอบพื้นฐานบางอย่างและไม่ประสบปัญหาใด ๆ
Sahil Sareen

74

Source.fromInputStream(is).mkString("") จะทำกรรมด้วย .....


จุดดี; Iterator[Char]แหล่งที่มาสร้างบางสิ่งบางอย่างที่ขยาย
Rex Kerr

8
โดยทั่วไปควรระบุการเข้ารหัสอักขระเมื่อทำสิ่งนี้ด้วย ในตอนท้าย: Source.fromInputStream(is)(Codec.UTF8).mkString
Connor Doyle

สิ่งนี้สั้น แต่ไม่ได้ปิดสตรีมในขณะที่รหัสจาวาดั้งเดิมทำ
รวย

@ Rich fromInputStream()ดูเหมือนจะปิดสตรีมอย่างน้อยใน Scala 2.11
jaco0646

2
@ jaco0646 - ไม่ได้ปิดสตรีม ฉันเพิ่งทดสอบ นี่คือรหัสสาธิตที่พิสูจน์ได้: gist.github.com/RichardBradley/bcd1a5e61fcc83e4e59f8b9b0bc2301c
รวย

13

วิธีที่เร็วกว่าในการดำเนินการนี้:

    private def inputStreamToString(is: InputStream) = {
        val inputStreamReader = new InputStreamReader(is)
        val bufferedReader = new BufferedReader(inputStreamReader)
        Iterator continually bufferedReader.readLine takeWhile (_ != null) mkString
    }

"เร็วกว่า"? แต่มันให้คำตอบแก่ฉันสำหรับวิธีการทำเมื่อฉันมีReaderและไม่ใช่InputStream.
BeepDog

3
เพียงข้ามบรรทัดแรกและส่งinputStreamReaderต่อไปยังวิธีการ
Kamil Lelonek

1
นี่อาจเป็นลำดับขนาดที่เร็วกว่า scala.io แหล่งที่มาใน Scala 2.11.7 ฉันเขียนเกณฑ์มาตรฐานขั้นพื้นฐานจริงๆของมันและโดยส่วนใหญ่แล้วไฟล์ขนาดใหญ่จะเร็วขึ้นประมาณ 5% (การทดสอบคือไฟล์ข้อความ ~ 35 MB) เร็วขึ้นถึง 2,800% สำหรับไฟล์ขนาดเล็ก (การทดสอบคือ ~ 30 KB) .
Colin Dean

2
สวย. Runtime.exec()รับการดิ้นรนหาทางออกที่สวยงามอ่านปัจจัยการผลิตที่มีขนาดใหญ่จาก เล็บนี้มัน
Pavel Lechev

ฉันจะระบุชุดอักขระที่จะใช้อย่างไร
นายท้าย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.