读取连续块

时间:2015-06-10 10:56:55

标签: scala large-files

我需要在Scala中读取一个大文件并以k位为单位处理它(k通常可以是65536)。作为一个简单的例子(但不是我想要的):

文件块为(f1, f2, ... fk)

我想计算SHA256(f1)+SHA256(f2)+...+ SHA256(fk)

这种计算可以仅使用常量存储和当前块递增地完成,而不需要其他块。

阅读文件的最佳方法是什么? (也许是使用延续的东西?)

编辑:链接的问题解决了问题,但并非总是如此,因为我正在查看的文件包含二进制数据。

2 个答案:

答案 0 :(得分:5)

这是一种使用Akka Streams的方法。这使用常量内存,并且可以在读取时处理文件块。

有关详细信息,请参阅本页底部的“Streaming File IO”。 http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-RC3/scala/stream-io.html

从一个简单的build.sbt文件开始:

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
        "com.typesafe.akka" %% "akka-stream-experimental" % "1.0-RC3"
)

有趣的部分是SourceFlowSinkSourceSynchronousFileSource,它读入大小为65536的大文件。从ByteString发出Source块大小,由Flow消耗,为每个块计算SHA256哈希值。最后,Sink使用Flow的输出并输出字节数组。您需要转换这些并使用fold对它们求和以获得总和。

import akka.stream.io._
import java.io.File
import scala.concurrent.Future
import akka.stream.scaladsl._
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer
import java.security.MessageDigest

object LargeFile extends App{
  implicit val system = ActorSystem("Sys")
  import system.dispatcher
  implicit val materializer = ActorFlowMaterializer()

   val file = new File("<path to large file>")

   val fileSource = SynchronousFileSource(file, 65536)

   val shaFlow = fileSource.map(chunk => sha256(chunk.toString))

   shaFlow.to(Sink.foreach(println(_))).run//TODO - Convert the byte[] and sum them using fold

   def sha256(s: String) = {
     val  messageDigest = MessageDigest.getInstance("SHA-256")
     messageDigest.digest(s.getBytes("UTF-8"))
   }
}

BYTE ARRAYS!

> run
[info] Running LargeFile 
[B@3d0587a6
[B@360cc296
[B@7fbb2192
...

答案 1 :(得分:0)

持续使用流创建摘要,我相信会生成迭代器

import java.File
import java.FileInputStream
import java.security.MessageDigest

val file = new File("test.in")
val is = new FileInputStream(file)

val md = MessageDigest.getInstance("SHA-256")

val bytes = Array.fill[Byte](65536)(0)

Stream
    .continually((is.read(bytes),bytes))
    .takeWhile(_._1 != -1)
    .foreach{ x => md.update(x._2,0,x._1) }

println(md.digest())
// prinln(md.digest().map("%02X" format _).mkString) // if you want hex string