So lesen Sie eine Datei als Byte-Array in Scala


77

Ich kann Unmengen von Beispielen finden, aber sie scheinen entweder hauptsächlich auf Java-Bibliotheken zu beruhen oder nur Zeichen / Zeilen / etc. Zu lesen.

Ich möchte nur eine Datei einlesen und ein Byte-Array mit Scala-Bibliotheken erhalten - kann mir jemand dabei helfen?


3
Ich denke, sich auf Java-Bibliotheken zu verlassen, ist das, was (fast?) Jeder tun würde, einschließlich der Scala-Bibliothek. Siehe zum Beispiel den Quellcode von scala.io.Source.
Philippe

2
Sie verwenden keine andere Sprache, sondern nur eine Standard-JVM-API, die sich als gut genug erwiesen hat, um nicht ersetzt zu werden!
Duncan McGregor

4
Wie werden die Java-Klassen Ihrer Meinung nach implementiert? Tief im Inneren gibt es irgendwo eine native Methode: Sie hat nur eine Signatur, keine Java-Implementierung und basiert auf einer betriebssystemspezifischen C-Implementierung. Betrügt das nicht auch? :)
Philippe

2
Es sollte gesagt werden, dass Scala auf .Net dies zu einem dringlicheren Problem macht.
Duncan McGregor

4
@Philippe: Sicher, und die Verwendung von C betrügt nur die Assemblierung: P ... Ich meinte nur, dass die Grenze zwischen Sprachen normalerweise ziemlich klar definiert ist, Scala und Java irgendwie ineinander verschmelzen.
Fgysin wieder Monica

Antworten:


134

Java 7:

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

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

Ich glaube, das ist der einfachste Weg. Nutzen Sie hier einfach vorhandene Tools. NIO.2 ist wunderbar.


1
Ich denke, dass jeder, der nicht an jvm <7 gebunden ist, dies verwenden sollte.
Fedesilva

45

Dies sollte funktionieren (Scala 2.8):

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

Ich denke, dies ist ein großartiges Beispiel für das Umschließen einer Java-API-Funktion, um die Stream-Semantik zu erhalten. Sehr geschätzt.
qu1j0t3

3
val bis = new java.io.BufferedInputStream(new java.io.FileInputStream(fileName)); Wenn Sie die Java-Pfade nicht importiert haben
BeniBela

1
Wird bei diesem Ansatz auch das Schließen der Datei benötigt oder ist dies implizit?
Max

1
Sie müssen es selbst schließen
Tony K.

13
Dieser Ansatz ist langsam, da jedes einzelne Byte verarbeitet werden muss. Im Idealfall sollten E / A-Vorgänge blockbasiert sein.
Dibbeke

6
val is = new FileInputStream(fileName)
val cnt = is.available
val bytes = Array.ofDim[Byte](cnt)
is.read(bytes)
is.close()

1
Es ist keine gültige Lösung. Aus javadoc von InputStream.available: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.
m.bemowski

5

Die Bibliothek scala.io.Source ist problematisch. Verwenden Sie sie NICHT zum Lesen von Binärdateien.

Der Fehler kann wie hier beschrieben reproduziert werden: https://github.com/liufengyun/scala-bug

In der Datei data.binenthält es die Hexadezimalzahl 0xea, die 11101010binär ist und 234in Dezimalzahl konvertiert werden sollte .

Die main.scalaDatei enthält zwei Möglichkeiten zum Lesen der Datei:

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
  }
}

Wenn ich starte scala main.scala, werden die Programmausgaben wie folgt ausgeführt:

Scala:205
Java:234

Die Java-Bibliothek generiert die korrekte Ausgabe, die Scala-Bibliothek nicht.


10
Wenn ich die Codierung auf einstelle Source.fromFile("data.bin", "ISO8859-1"), funktioniert es gut.
Fengyun Liu

6
Vielleicht ist es hilfreich, aber das ist wirklich keine Antwort. Das Einführen eines neuen Problems in eine Antwort ist nicht konstruktiv und gehört woanders hin.
Benjamin


2

Sie können Apache Commons Compress verwenden IOUtils

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

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

1
Ich musste import org.apache.commons.io.IOUtils anstelle des vorgeschlagenen Imports importieren.
27.

0

Ich habe den folgenden Code verwendet, um eine CSV-Datei zu lesen.

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() 
}

1
Bei einer so alten Frage (vor über 9 Jahren gestellt) und bei so vielen bereits eingereichten Antworten ist es hilfreich, darauf hinzuweisen, wie sich Ihre neue Antwort von den vorherigen Antworten unterscheidet. (Und einschließlich Code, der
auskommentiert wurde
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.