Scala:输入流到数组 [字节]
Posted
技术标签:
【中文标题】Scala:输入流到数组 [字节]【英文标题】:Scala: InputStream to Array[Byte] 【发布时间】:2011-06-21 18:45:12 【问题描述】:对于 Scala,从 InputStream 读取到字节数组的最佳方法是什么?
我可以看到您可以将 InputStream 转换为 char 数组
Source.fromInputStream(is).toArray()
【问题讨论】:
【参考方案1】:怎么样:
Stream.continually(is.read).takeWhile(_ != -1).map(_.toByte).toArray
更新:使用 LazyList 代替 Stream
(因为 Stream
在 Scala 3 中已弃用)
LazyList.continually(is.read).takeWhile(_ != -1).map(_.toByte).toArray
【讨论】:
你能解释一下这个和问题中的变体之间的区别吗? @Jus12 我正在寻找一个字节数组。我的问题是一种获取 char 数组的方法。 不会创建一个巨大的链表,然后将其转换为数组吗?在时间或内存方面,这看起来效率不高。 看起来这毕竟没有创建一个链表。 Stream.continually 产生一个迭代器,takeWhile
和 map
似乎将迭代器转换为迭代器。例如。在 Scala 2.9.3 REPL 中评估 Array(1, 2, 3, 4, -1).iterator.takeWhile(-1 !=).map(_.toByte)
给我 Iterator[Byte] = non-empty iterator
。
这似乎对我造成了 OOM 错误。事情最终被 GC 处理了,但峰值超出了我的服务器可以处理的范围。【参考方案2】:
刚刚通过替换消除了我们服务器代码中的瓶颈
Stream.continually(request.getInputStream.read()).takeWhile(_ != -1).map(_.toByte).toArray
与
org.apache.commons.io.IOUtils.toByteArray(request.getInputStream)
或者在纯 Scala 中:
def bytes(in: InputStream, initSize: Int = 8192): Array[Byte] =
var buf = new Array[Byte](initSize)
val step = initSize
var pos, n = 0
while (
if (pos + step > buf.length) buf = util.Arrays.copyOf(buf, buf.length << 1)
n = in.read(buf, pos, step)
n != -1
) pos += n
if (pos != buf.length) buf = util.Arrays.copyOf(buf, pos)
buf
在任何情况下都不要忘记关闭打开的输入流:
val in = request.getInputStream
try bytes(in) finally in.close()
【讨论】:
那是 org.apache.commons.io.IOUtils.toByteArray,以防有人想知道。 这肯定感觉更快。有人对较大的文件进行过任何基准测试或测试吗? 谢谢。使用 Apache Spark 运行它时,我遇到了 GC Overhead 错误的巨大问题,我的任务有 90% 的时间都花在了 GC 上。替换为toByteArray
大大加快了速度。
重要的是要指出这个解决方案如何真正大大超越替代方案,你有像 map(_.toByte)
这样的东西逐字节迭代输入......你正在做这个吗大数据!【参考方案3】:
与 Eastsun 的回答类似...我一开始是评论,但最终变得有点长!
我建议不要使用Stream
,如果持有对头元素的引用,那么流很容易消耗大量内存。
鉴于您只会在文件中读取一次,那么Iterator
是一个更好的选择:
def inputStreamToByteArray(is: InputStream): Array[Byte] =
Iterator continually is.read takeWhile (-1 !=) map (_.toByte) toArray
【讨论】:
【参考方案4】:import scala.tools.nsc.io.Streamable
Streamable.bytes(is)
不记得最近的时间:可能以天为单位。回到2.8,更像
new Streamable.Bytes def inputStream() = is toByteArray
【讨论】:
使用 scala.tools 包中的东西安全吗?它们甚至是标准库的一部分吗? 没有。但是,如果您想知道如何编写它,就在这里。 它现在似乎已经转移到更标准的scala.reflect.io
包。
scala.reflect.io.Streamable.bytes
【参考方案5】:
使用Scala IO,这应该可以:
def inputStreamToByteArray(is: InputStream): Array[Byte] =
Resource.fromInputStream(in).byteArray
【讨论】:
【参考方案6】:使用better-files,您可以简单地使用is.bytes
【讨论】:
better.files 应该只在标准库中。它好多了。此外,如果您想要Array[Byte]
,则需要使用is.byteArray
。【参考方案7】:
Source.fromInputStream(is).map(_.toByte).toArray
【讨论】:
这在二进制/错误编码的文本文件上失败:***.com/questions/13327536/…【参考方案8】:基于流和 ByteArraOutputStream 的缓冲版本解决方案如何最大限度地减少最终数组增长的样板?
val EOF: Int = -1
def readBytes(is: InputStream, bufferSize: Int): Array[Byte] =
val buf = Array.ofDim[Byte](bufferSize)
val out = new ByteArrayOutputStream(bufferSize)
Stream.continually(is.read(buf)) takeWhile _ != EOF foreach n =>
out.write(buf, 0, n)
out.toByteArray
【讨论】:
【参考方案9】:这是一种使用 scalaz-stream 的方法:
import scalaz.concurrent.Task
import scalaz.stream._
import scodec.bits.ByteVector
def allBytesR(is: InputStream): Process[Task, ByteVector] =
io.chunkR(is).evalMap(_(4096)).reduce(_ ++ _).lastOr(ByteVector.empty)
【讨论】:
可能没有理由减少,这会破坏流的增量特性 原因是题目要求的是字节数组。【参考方案10】:我们可以使用 Google API ByteStreams
com.google.common.io.ByteStreams
将流传递给 ByteStreams.toByteArray 方法进行转换
ByteStreams.toByteArray(stream)
【讨论】:
【参考方案11】:def inputStreamToByteArray(is: InputStream): Array[Byte] =
val buf = ListBuffer[Byte]()
var b = is.read()
while (b != -1)
buf.append(b.byteValue)
b = is.read()
buf.toArray
【讨论】:
List[Byte] 有方法“add”吗?以上是关于Scala:输入流到数组 [字节]的主要内容,如果未能解决你的问题,请参考以下文章
将字节数组输入流拷贝成字节数组输出流,将ByteArrayInputStream转成ByteArrayOutputStream