如何将文件读入InputStream,然后将其写入Scala中的OutputStream?

时间:2011-08-03 14:12:24

标签: java scala integration inputstream outputstream

我正在尝试使用Scala中的基本Java代码从文件读取并写入 OutputStream ,但是当我使用通常的 while(!= -1)给我一个警告“比较Unit和Int的类型!=将永远产生真实”。

代码如下:

    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-like 解决方案。

5 个答案:

答案 0 :(得分:39)

你可以这样做:

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

答案 1 :(得分:17)

如果这很慢:

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()

答案 2 :(得分:7)

赋值语句总是在Scala中返回Unit,因此read = input.read返回Unit,它永远不等于-1。你可以这样做:

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

答案 3 :(得分:3)

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()
}

答案 4 :(得分:0)

我们可以使用类型类以通用和类型安全的方式将输入流复制到输出流。类型类是一个概念。这是多态性的一种方法。特别是,它是参数多态,因为多态行为是使用参数编码的。在我们的例子中,我们的参数将是Scala特征的通用类型。

让我们制作Reader[I]Writer[O]个特征,其中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].applyReader[I]值,我们会说Writer[O]会起作用。这将使我们能够无缝地调用CopyStreams(输入,输出)。

但重要的是,请注意此实现是通用的。它对独立于实际流实现的类型进行操作。

在我的特定用例中,我需要将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代码而无需更改它!