我需要在Scala中读取一个大文件并以k位为单位处理它(k通常可以是65536)。作为一个简单的例子(但不是我想要的):
文件块为(f1, f2, ... fk)
。
我想计算SHA256(f1)+SHA256(f2)+...+ SHA256(fk)
这种计算可以仅使用常量存储和当前块递增地完成,而不需要其他块。
阅读文件的最佳方法是什么? (也许是使用延续的东西?)
编辑:链接的问题解决了问题,但并非总是如此,因为我正在查看的文件包含二进制数据。答案 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"
)
有趣的部分是Source
,Flow
和Sink
。 Source
是SynchronousFileSource
,它读入大小为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