2015-06-10 18 views
6

Tôi cần đọc một tệp lớn trong Scala và xử lý nó theo khối bit k (k có thể là 65536 thường). Như một ví dụ đơn giản (nhưng không phải là những gì tôi muốn):Đọc các tệp rất lớn (~ 1 TB) trong các khối liên tiếp

khối tệp là (f1, f2, ... fk).

tôi muốn để tính SHA256(f1)+SHA256(f2)+...+ SHA256(fk)

Như một tính toán có thể được thực hiện từng bước chỉ sử dụng lưu trữ liên tục và khối hiện tại mà không cần các khối khác.

Cách tốt nhất để đọc tệp là gì? (có lẽ một cái gì đó sử dụng tiếp tục?)

CHỈNH SỬA: Loại câu hỏi được liên kết giải quyết vấn đề nhưng không phải lúc nào, vì tệp tôi đang xem chứa dữ liệu nhị phân.

+0

@Christian, Không, đây không phải lặp lại của câu hỏi được trích dẫn. – Biswanath

+0

Tôi không thể hiểu điều này trùng lặp với câu hỏi được trích dẫn. Các câu hỏi khác nói về một tập tin csv dựa trên văn bản, câu hỏi này là đối phó với một "không phải văn bản dựa trên csv" tập tin. Câu trả lời của câu hỏi khác không nên áp dụng. Tôi thực sự nghi ngờ ai đã từng đánh dấu điều này là trùng lặp nếu họ đọc cả hai câu hỏi một cách đầy đủ. – Biswanath

Trả lời

4

Đây là cách tiếp cận sử dụng Luồng Akka. Điều này sử dụng bộ nhớ liên tục và có thể xử lý các khối tệp khi chúng được đọc.

Xem "Tệp IO truyền trực tuyến" ở cuối trang này để biết thêm thông tin. http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-RC3/scala/stream-io.html

Bắt đầu với một tập tin đơn giản build.sbt:

scalaVersion := "2.11.6" 

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

Các bộ phận thú vị là những Source, Flow, và Sink. Source là một số SynchronousFileSource đọc trong một tệp lớn có kích thước chunk là 65536. Một kích thước chunk ByteString được phát ra từ Source và được tiêu thụ bởi một Flow để tính toán giá trị băm SHA256 cho mỗi đoạn. Cuối cùng, Sink tiêu thụ đầu ra từ Flow và in các mảng byte ra. Bạn sẽ muốn chuyển đổi chúng và tổng hợp chúng bằng cách sử dụng fold để nhận tổng số tiền.

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 
[[email protected] 
[[email protected] 
[[email protected] 
... 
0

Tạo tiêu hóa bằng cách sử dụng dòng liên tục, mà tôi tin rằng tạo ra một iterator

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 
+0

cala.collection.immutable.Stream được ghi nhớ, sẽ đọc toàn bộ nội dung vào bộ nhớ (theo http://stackoverflow.com/questions/4255021/how-do-i-read-a-large-csv-file- với-scala-stream-class # answer-4255338) – mikebridge

Các vấn đề liên quan