Scala'da bir InputStream'i String'e dönüştürmenin deyimsel yolu


111

Java'da InputStream'i String'e dönüştürmek için kullandığım kullanışlı bir işlevim var. Scala'ya doğrudan bir çeviri:

  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
  }

Bunu ölçekli olarak yapmanın deyimsel bir yolu var mı?

Yanıtlar:


197

Scala için> = 2.11

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

Scala <2.11 için:

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

hemen hemen aynı şeyi yapar. Yine de neden çizgiler almak ve sonra hepsini bir araya getirmek istediğinizden emin değilim. Akışın engellenmediğini varsayabilirseniz, sadece kullanabilir .available, her şeyi bir bayt dizisi halinde okuyabilir ve bundan doğrudan bir dize oluşturabilirsiniz.


2
Kendimi kullanmamın olası bir nedeni, farklı işletim sistemlerinde satır sonlarını normalleştirmektir.
Kevin Wright

Raam'ın yanıtı da harika (ve biraz daha özlü), ancak Rex'i yanıt olarak işaretliyor, çünkü daha spesifik olarak örnekteki gibi. Satırları tekrar bir araya getirmek birkaç durumda spesifikti, ancak bana bu kodu, bunu yapmanın pek uygun olmadığı yerlerde kullandığımı hatırlattınız.
bballant

çözüm getLines () kullandığından çok güvenli değildir; giriş akışında "yeni satır" karakterleri yoksa ne olur? sonra her şey bloke olur
Paul Sabou

Oldukça kötü bir çözüm. Ya girdi akışı DOS satır sonları içeriyorsa (\ r \ n). Bunlar bu yöntemle kaldırılacaktır. Ayrıca, mkString bir arabellek kullansa da, karakter bloklarını okumak kesinlikle daha hızlı olacaktır.
Dibbeke

1
@RexKerr Cevabınızda bahsettiğiniz "performans hatasını" belirtebilir misiniz? Her iki sürümü de bazı temel testlerle test ettim ve herhangi bir sorunla karşılaşmadım.
Sahil Sareen

74

Source.fromInputStream(is).mkString("") tapuyu da yapacak .....


İyi bir nokta; kaynak genişleyen bir şey yaratır Iterator[Char].
Rex Kerr

8
Bu tür şeyleri yaparken karakter kodlamasını da belirtmek genellikle iyi bir uygulamadır. Bunun için: Source.fromInputStream(is)(Codec.UTF8).mkString
Connor Doyle

Bu kısa, ancak akışı kapatmaz, oysa orijinal java kodu kapattı.
Zengin

@Rich, fromInputStream()en azından Scala 2.11'de akışı kapatıyor gibi görünüyor.
jaco0646

2
@ jaco0646 - akışı kapatmaz. Az önce test ettim. İşte bunu kanıtlayan demo kodu: gist.github.com/RichardBradley/bcd1a5e61fcc83e4e59f8b9b0bc2301c
Rich

13

Bunu yapmanın daha hızlı yolu:

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

"Daha hızlı"? Ama bana sadece a varken Readerve değilken bunu nasıl yapacağıma dair cevap verdi InputStream.
BeepDog

3
İlk satırı atlayın ve inputStreamReaderyönteme geçin.
Kamil Lelonek

1
Bu, potansiyel olarak scala.io'dan daha hızlı bir büyüklük sırasıdır. Scala 2.11.7'deki Kaynak. Gerçekten temel bir ölçüt yazdım ve çoğu zaman, büyük dosyalar için yaklaşık% 5 daha hızlıydı (test ~ 35 MB metin dosyasıydı), küçük dosyalar için% 2,800'e kadar daha hızlıydı (test ~ 30 KB idi) .
Colin Dekan

2
Güzel. Büyük girdileri okuyan zarif bir çözüm için mücadele ediyorum Runtime.exec(). Bu onu çiviliyor.
Pavel Lechev

Kullanılacak bir karakter kümesini nasıl belirtebilirim?
Wheeler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.