【问题标题】:How to read a file as a byte array in Scala如何在Scala中将文件作为字节数组读取
【发布时间】:2011-11-27 17:28:16
【问题描述】:

我可以找到大量示例,但它们似乎要么主要依赖于 Java 库,要么只是读取字符/行/等。

我只想读入一些文件并获得一个带有 scala 库的字节数组 - 有人可以帮我吗?

【问题讨论】:

  • 我认为依赖 Java 库是(几乎?)每个人都会做的事情,包括 Scala 库。参见例如 scala.io.Source 的源代码。
  • 您使用的不是其他语言,只是一个标准的 JVM API,它已被证明足够好,不需要替换!
  • 那么,您认为Java 类是如何实现的?在内心深处,有一个本地方法:它只有一个签名,没有 Java 实现,并且依赖于特定于操作系统的 C 实现。这不也是作弊吗? :)
  • 应该说.Net上的Scala确实让这个问题变得更加紧迫。
  • @Philippe:当然,使用 C 只是在汇编上作弊:P...我的意思是,语言之间的边界通常是相当明确的,Scala 和 Java 有点融为一体彼此。

标签: scala io bytearray


【解决方案1】:

Java 7:

import java.nio.file.{Files, Paths}

val byteArray = Files.readAllBytes(Paths.get("/path/to/file"))

我相信这是最简单的方法。只是在这里利用现有的工具。 NIO.2 很棒。

【讨论】:

  • 我认为没有绑定到 jvm
【解决方案2】:

这应该可以工作(Scala 2.8):

val bis = new BufferedInputStream(new FileInputStream(fileName))
val bArray = Stream.continually(bis.read).takeWhile(-1 !=).map(_.toByte).toArray

【讨论】:

  • 我认为这是包装 Java API 函数以获取 Stream 语义的一个很好的例子。非常感谢。
  • val bis = new java.io.BufferedInputStream(new java.io.FileInputStream(fileName)); 如果您没有导入 java 路径
  • 使用这种方法,是也需要关闭文件还是隐式的?
  • 你需要自己关闭
  • 这种方法很慢,因为它需要处理每个字节。理想情况下,I/O 操作应该是基于块的。
【解决方案3】:

scala.io.Source有问题,不要用它来读取二进制文件。

可以按照此处的说明重现错误:https://github.com/liufengyun/scala-bug

data.bin文件中,包含十六进制的0xea,即二进制的11101010,需要转换成十进制的234

main.scala 文件包含两种读取文件的方式:

import scala.io._
import java.io._

object Main {
  def main(args: Array[String]) {
    val ss = Source.fromFile("data.bin")
    println("Scala:" + ss.next.toInt)
    ss.close

    val bis = new BufferedInputStream(new FileInputStream("data.bin"))
    println("Java:" + bis.read)
    bis.close
  }
}

当我运行scala main.scala时,程序输出如下:

Scala:205
Java:234

Java 库生成正确的输出,而 Scala 库没有。

【讨论】:

  • 如果我将编码设置为Source.fromFile("data.bin", "ISO8859-1"),效果很好。
  • 也许有用,但实际上,这不是答案。在答案中引入新问题是不具建设性的,属于其他地方。
【解决方案4】:
val is = new FileInputStream(fileName)
val cnt = is.available
val bytes = Array.ofDim[Byte](cnt)
is.read(bytes)
is.close()

【讨论】:

  • 这不是一个有效的解决方案。来自 InputStream.available 的 javadoc:Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
【解决方案5】:

您也可以考虑使用scalax.io

scalax.io.Resource.fromFile(fileName).byteArray

【讨论】:

  • 注意到该存储库的最后一次操作是 6 年前 - 它仍然相关吗?
【解决方案6】:

您可以使用Apache Commons CompressIOUtils

import org.apache.commons.compress.utils.IOUtils

val file = new File("data.bin")
IOUtils.toByteArray(new FileInputStream(file))

【讨论】:

  • 我不得不导入 import org.apache.commons.io.IOUtils 而不是建议的导入。
【解决方案7】:

使用 Scala Future 和 Java NIO2 进行异步文件读取

  def readFile(path: Path)(implicit ec: ExecutionContext): Future[Array[Byte]] = {
    val p = Promise[Array[Byte]]()
    try {
      val channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ)
      val buffer = ByteBuffer.allocate(channel.size().toInt);
      channel.read(buffer, 0L, buffer, onComplete(channel, p))
    }
    catch {
      case t: Exception => p.failure(t)
    }
    p.future
  }

  private def onComplete(channel: AsynchronousFileChannel, p: Promise[Array[Byte]]) = {
    new CompletionHandler[Integer, ByteBuffer]() {
      def completed(res: Integer, buffer: ByteBuffer): Unit = {
        p.complete(Try {
          buffer.array()
        })
      }

      def failed(t: Throwable, buffer: ByteBuffer): Unit = {
        p.failure(t)
      }
    }
  }

【讨论】:

    【解决方案8】:

    我已使用以下代码读取 CSV 文件。

    import scala.io.StdIn.readLine
    import scala.io.Source.fromFile
    
    readFile("C:/users/xxxx/Downloads/", "39025968_ccccc_1009.csv")
    
    def readFile(loc :String,filenm :String): Unit ={
    
      var flnm = fromFile(s"$loc$filenm") // Imported fromFile package
    
      println("Files testing")
      /*for (line <- flnm.getLines()) {
        printf("%4d %s\n", line.length, line)
      }*/
      flnm.getLines().foreach(println) // getLines() is imported from readLines.
      flnm.close() 
    }
    

    【讨论】:

    • 对于这么老的问题(9 年前提出的问题),并且已经提交了这么多答案,指出您的新答案与以前的答案有何不同是很有帮助的。 (包括被注释掉的代码看起来很草率。)
    • 是的.. 其他答案清楚地显示了返回的字节数组。这个真的不清楚
    猜你喜欢
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 2013-07-31
    • 2014-03-30
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多