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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6927873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:18:08  来源:igfitidea点击:

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

javascalaintegrationinputstreamoutputstream

提问by Maurício Linhares

I'm trying to use basic Java code in Scala to read from a file and write to an OutputStream, but when I use the usual while( != -1 )in Scala gives me a warning "comparing types of Unit and Int with != will always yield true".

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

The code is as follows:

代码如下:

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

How am I supposed to write from an input stream to an output stream in Scala?

我应该如何在 Scala 中从输入流写入输出流?

I'm mostly interested in a Scala-likesolution.

我最感兴趣的是类似 Scala 的解决方案。

回答by Daniel C. Sobral

You could do this:

你可以这样做:

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

回答by Yaroslav

If this is slow:

如果这很慢:

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

you can expand it:

你可以扩展它:

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

回答by Kim Stebel

Assignment statements always return Unit in Scala, so read = input.readreturns Unit, which never equals -1. You can do it like this:

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

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

回答by Knut Arne Vedaa

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

回答by Malcolm

We can copy an inputstream to an outputstream in a generic and type-safe manner using typeclasses. A typeclass is a concept. It's one approach to polymorphism. In particular, it's parametric polymorphismbecause the polymorphic behavior is encoded using parameters. In our case, our parameters will be generic types to Scala traits.

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

Let's make Reader[I]and Writer[O]traits, where Iand Oare input and output stream types, respectively.

让我们使用 makeReader[I]Writer[O]traits,其中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
}

We can now make a generic copy method that can operate on things that subscribe to these interfaces.

我们现在可以创建一个通用的复制方法,该方法可以对订阅这些接口的事物进行操作。

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

Note the implicit rand wparameters here. Essentially, we're saying that CopyStreams[I,O].applywill work iff there are Reader[I]and a Writer[O]values in scope. This will make us able to call CopyStreams(input, output) seamlessly.

注意这里的隐式rw参数。本质上,我们是说,CopyStreams[I,O].apply如果范围中Reader[I]Writer[O]值并且存在值,这将起作用。这将使我们能够无缝地调用 CopyStreams(input, output)。

Importantly, however, note that this implementation is generic. It operates on types that are independent of actual stream implementations.

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

In my particular use case, I needed to copy S3 objects to local files. So I made the following implicit values.

在我的特定用例中,我需要将 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)
  }
}

So now I can do the following:

所以现在我可以执行以下操作:

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

And if we ever need to copy different stream types, we only need to write a new Readeror Writerimplicit value. We can use the CopyStreamscode without changing it!

如果我们需要复制不同的流类型,我们只需要编写一个新的ReaderWriter隐式的值。我们可以CopyStreams不用修改代码就可以使用!