簡體   English   中英

如何將文件讀取到 InputStream 然后將其寫入 Scala 中的 OutputStream?

[英]How can I read a file to an InputStream then write it into an OutputStream in Scala?

我正在嘗試使用 Scala 中的基本 Java 代碼從文件中讀取並寫入OutputStream ,但是當我在 Scala 中使用通常的while( != -1 )時給了我一個警告“將 Unit 和 Int 的類型與 ! = 將始終產生 true”。

代碼如下:

    val file = this.cache.get(imageFileEntry).getValue().asInstanceOf[File]
    response.setContentType( "image/%s".format( imageDescription.getFormat() ) )

    val input = new BufferedInputStream( new FileInputStream( file ) )
    val output = response.getOutputStream()

    var read : Int = -1

    while ( ( read = input.read ) != -1 ) {
        output.write( read )
    }

    input.close()
    output.flush()

我應該如何在 Scala 中從輸入流寫入輸出流?

我最感興趣的是類似 Scala 的解決方案。

你可以這樣做:

Iterator 
.continually (input.read)
.takeWhile (-1 !=)
.foreach (output.write)

如果這很慢:

Iterator 
.continually (input.read)
.takeWhile (-1 !=)
.foreach (output.write)

你可以擴展它:

val bytes = new Array[Byte](1024) //1024 bytes - Buffer size
Iterator
.continually (input.read(bytes))
.takeWhile (-1 !=)
.foreach (read=>output.write(bytes,0,read))
output.close()

賦值語句在 Scala 中總是返回 Unit,所以read = input.read返回 Unit,它從不等於 -1。 你可以這樣做:

while ({read = input.read; read != -1}) {
  output.write(read)
}
def stream(inputStream: InputStream, outputStream: OutputStream) =
{
  val buffer = new Array[Byte](16384)

  def doStream(total: Int = 0): Int = {
    val n = inputStream.read(buffer)
    if (n == -1)
      total
    else {
      outputStream.write(buffer, 0, n)
      doStream(total + n)
    }
  }

  doStream()
}

我們可以使用類型類以通用和類型安全的方式將輸入流復制到輸出流。 類型類是一個概念。 這是多態的一種方法。 特別是,它是參數多態性,因為多態行為是使用參數編碼的。 在我們的例子中,我們的參數將是 Scala 特征的泛型類型。

讓我們創建Reader[I]Writer[O] trait,其中IO分別是輸入和輸出流類型。

trait Reader[I] {
  def read(input: I, buffer: Array[Byte]): Int
}

trait Writer[O] {
  def write(output: O, buffer: Array[Byte], startAt: Int, nBytesToWrite: Int): Unit
}

我們現在可以創建一個通用的復制方法,該方法可以對訂閱這些接口的事物進行操作。

object CopyStreams {

  type Bytes = Int

  def apply[I, O](input: I, output: O, chunkSize: Bytes = 1024)(implicit r: Reader[I], w: Writer[O]): Unit = {
    val buffer = Array.ofDim[Byte](chunkSize)
    var count = -1

    while ({count = r.read(input, buffer); count > 0})
      w.write(output, buffer, 0, count)
  }
}

注意這里隱含的rw參數。 本質上,我們是說CopyStreams[I,O].apply將工作,如果范圍中有Reader[I]Writer[O]值。 這將使我們能夠無縫地調用 CopyStreams(input, output)。

但重要的是,請注意此實現是通用的。 它對獨立於實際流實現的類型進行操作。

在我的特定用例中,我需要將 S3 對象復制到本地文件。 所以我做了以下隱含值。

object Reader {

  implicit val s3ObjectISReader = new Reader[S3ObjectInputStream] {
    @inline override def read(input: S3ObjectInputStream, buffer: Array[Byte]): Int =
      input.read(buffer)
  }
}


object Writer {

  implicit val fileOSWriter = new Writer[FileOutputStream] {
    @inline override def write(output: FileOutputStream,
                               buffer: Array[Byte],
                               startAt: Int,
                               nBytesToWrite: Int): Unit =
      output.write(buffer, startAt, nBytesToWrite)
  }
}

所以現在我可以執行以下操作:

val input:S3ObjectStream = ...
val output = new FileOutputStream(new File(...))
import Reader._
import Writer._
CopyStreams(input, output)
// close and such...

如果我們需要復制不同的流類型,我們只需要編寫一個新的ReaderWriter隱式值。 我們可以使用CopyStreams代碼而無需更改它!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM