Подтвердить что ты не робот

Как я могу прочитать файл в InputStream, а затем записать его в OutputStream в Scala?

Я пытаюсь использовать базовый код Java в Scala для чтения из файла и писать в OutputStream, но когда я использую обычный while (!= -1) в Scala дает мне предупреждение "сравнение типов 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 -like.

4b9b3361

Ответ 1

Вы можете сделать это:

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

Ответ 2

Если это медленно:

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

Ответ 3

Операторы присваивания всегда возвращают Unit в Scala, поэтому read = input.read возвращает Unit, который никогда не равен -1. Вы можете сделать это следующим образом:

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

Ответ 4

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

Ответ 5

Мы можем скопировать входной поток в выходной поток в универсальном и безопасном типе с использованием классов типов. Стандартная концепция - это концепция. Это один подход к полиморфизму. В частности, это параметрический полиморфизм, поскольку полиморфное поведение кодируется с использованием параметров. В нашем случае наши параметры будут типичными типами для Scala признаков.

Пусть создаются черты Reader[I] и Writer[O], где I и O - соответственно типы ввода и вывода.

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

Обратите внимание на неявные параметры r и w. По существу, мы говорим, что CopyStreams[I,O].apply будет работать, если в области есть значения Reader[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...

И если нам когда-либо понадобится копировать разные типы потоков, нам нужно только написать новое Reader или Writer неявное значение. Мы можем использовать код CopyStreams, не меняя его!