Как я могу прочитать файл в InputStream и записать его в OutputStream в Scala? - PullRequest
18 голосов
/ 03 августа 2011

Я пытаюсь использовать базовый код 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?

Меня больше всего интересует Скала-подобное решение.

Ответы [ 5 ]

40 голосов
/ 03 августа 2011

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

Iterator 
.continually (input.read)
.takeWhile (-1 !=)
.foreach (output.write)
17 голосов
/ 31 мая 2013

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

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()
7 голосов
/ 03 августа 2011

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

while ({read = input.read; read != -1}) {
  output.write(read)
}
3 голосов
/ 03 августа 2011
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()
}
0 голосов
/ 14 апреля 2015

Мы можем скопировать входной поток в выходной поток общим и безопасным для типов способом, используя классы типов.Класс типов - это понятие.Это один из подходов к полиморфизму.В частности, это параметрический полиморфизм , потому что полиморфное поведение кодируется с использованием параметров.В нашем случае наши параметры будут универсальными типами для черт 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 (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...

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...