Cách đơn giản để chuyển đổi InputStream thành một chuỗi trong Scala


111

Tôi có một hàm tiện dụng mà tôi đã sử dụng trong Java để chuyển đổi InputStream thành Chuỗi. Đây là bản dịch trực tiếp sang 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
  }

Có một cách thành ngữ để làm điều này trong scala không?

Câu trả lời:


197

Đối với Scala> = 2,11

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

Đối với Scala <2,11:

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

làm khá nhiều điều tương tự. Tuy nhiên, không chắc tại sao bạn lại muốn có các đường kẻ và sau đó dán chúng lại với nhau. Nếu bạn có thể giả sử luồng không chặn, bạn có thể sử dụng .available, đọc toàn bộ nội dung vào một mảng byte và tạo một chuỗi trực tiếp từ đó.


2
Một lý do có thể mà bản thân tôi đã sử dụng là chuẩn hóa các kết thúc dòng trên các hệ điều hành khác nhau.
Kevin Wright

Câu trả lời của Raam cũng tuyệt vời (và ngắn gọn hơn một chút), nhưng đánh dấu câu trả lời của Rex là THEO, bởi vì nó cụ thể hơn giống như ví dụ. Việc dán các dòng lại với nhau là một vài trường hợp cụ thể, nhưng bạn đã nhắc tôi rằng tôi đã sử dụng mã này ở những nơi không hoàn toàn thích hợp để làm điều đó.
bballant

giải pháp không an toàn lắm vì nó sử dụng getLines (); điều gì sẽ xảy ra nếu luồng đầu vào không có ký tự "dòng mới"? sau đó các khối điều toàn
Paul Sabou

Một giải pháp khá tệ. Điều gì sẽ xảy ra nếu dòng đầu vào chứa phần cuối dòng DOS (\ r \ n). Chúng sẽ được loại bỏ bằng phương pháp này. Ngoài ra, mặc dù mkString sử dụng bộ đệm, nhưng chắc chắn việc đọc các khối ký tự sẽ nhanh hơn.
Dibbeke

1
@RexKerr Bạn có thể vui lòng chỉ ra "lỗi hiệu suất" mà bạn đã đề cập trong câu trả lời của mình không. Tôi đã thử nghiệm cả hai phiên bản với một số testcase cơ bản và không gặp vấn đề gì.
Sahil Sareen

74

Source.fromInputStream(is).mkString("") cũng sẽ làm chứng thư .....


Điểm tốt; nguồn tạo ra một cái gì đó mở rộng Iterator[Char].
Rex Kerr

8
Nói chung, bạn cũng nên chỉ định mã hóa ký tự khi làm việc này. Cuối cùng: Source.fromInputStream(is)(Codec.UTF8).mkString
Connor Doyle

Đây là ngắn gọn, nhưng nó không đóng luồng, ngược lại mã java ban đầu đã làm.
Giàu

@Rich, fromInputStream()dường như để đóng luồng, ít nhất là trong Scala 2.11.
jaco0646 3/12/16

2
@ jaco0646 - nó không đóng luồng. Tôi mới thử nghiệm. Đây là mã demo chứng minh điều đó: gist.github.com/RichardBradley/bcd1a5e61fcc83e4e59f8b9b0bc2301c
Rich

13

Cách nhanh hơn để làm điều này:

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

"nhanh hơn"? Nhưng nó cung cấp cho tôi câu trả lời về cách làm điều đó khi tôi chỉ có một Readervà không một InputStream.
BeepDog

3
Chỉ cần bỏ qua dòng đầu tiên và chuyển inputStreamReaderđến phương thức.
Kamil Lelonek,

1
Đây có thể là một thứ tự cường độ nhanh hơn scala.io. Nguồn trong Scala 2.11.7. Tôi đã viết một điểm chuẩn thực sự cơ bản của nó và hầu hết thời gian, nó nhanh hơn khoảng 5% đối với các tệp lớn (kiểm tra là tệp văn bản ~ 35 MB) tất cả các cách nhanh hơn tới 2.800% đối với tệp nhỏ (kiểm tra là ~ 30 KB) .
Colin Dean

2
Xinh đẹp. Đang đấu tranh cho một giải pháp thanh lịch đọc đầu vào lớn từ Runtime.exec(). Cái này đóng đinh nó.
Pavel Lechev

Làm cách nào để chỉ định một bộ ký tự để sử dụng?
xe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.