82 votes

Comment lire un fichier sous forme de tableau d'octets en Scala ?

Je peux trouver des tonnes d'exemples, mais ils semblent soit s'appuyer principalement sur des bibliothèques Java, soit se contenter de lire des caractères, des lignes, etc.

Je veux juste lire un fichier et obtenir un tableau d'octets avec les bibliothèques Scala. Quelqu'un peut-il m'aider ?

3 votes

Je pense que s'appuyer sur les bibliothèques Java est ce que (presque ?) tout le monde ferait, y compris la bibliothèque Scala. Voir par exemple le code source de scala.io.Source.

0 votes

Je sais que Scala s'appuie sur Java. Mais quel est l'intérêt d'un langage où je ne peux même pas faire de simples entrées/sorties de fichier sans utiliser une autre langue ?

2 votes

Vous n'utilisez pas un langage différent, mais simplement une API standard de la JVM qui s'est avérée suffisamment bonne pour ne pas être remplacée !

138voto

Vladimir Matveev Points 16593

Java 7 :

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

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

Je pense que c'est la manière la plus simple possible. Je ne fais que tirer parti des outils existants. NIO.2 est merveilleux.

1 votes

Je pense que tous ceux qui ne sont pas liés à jvm < 7 devraient l'utiliser.

47voto

Jus12 Points 4580

Cela devrait fonctionner (Scala 2.8) :

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

0 votes

Je pense qu'il s'agit d'un excellent exemple d'habillage d'une fonction de l'API Java pour obtenir la sémantique Stream. Merci beaucoup.

3 votes

val bis = new java.io.BufferedInputStream(new java.io.FileInputStream(fileName)); si vous n'avez pas importé les chemins java

1 votes

En utilisant cette approche, la fermeture du fichier est-elle également nécessaire ou est-elle implicite ?

20voto

Debilski Points 28586

Editar: Comme l'ont fait remarquer certains commentaires sur le SO et la ailleurs Si l'on se fie à ce qui précède, cette solution n'est peut-être plus la meilleure (et je ne sais pas si elle l'a jamais été). Je vous invite à consulter les autres réponses ici, à faire vos propres tests et à mettre en avant ces autres réponses si elles fonctionnent. Malheureusement, bien sûr, je ne peux pas désactiver cette réponse moi-même.

scala.io.Source.fromFile(fileName).map(_.toByte).toArray

(ou toArray avant map ?)

Notez que cela peut laisser le fichier ouvert, vous devrez donc probablement le faire :

val source = scala.io.Source.fromFile(fileName)
val byteArray = source.map(_.toByte).toArray
source.close()

Modifier : Si vous avez besoin de charger un encodage spécifique, vous pouvez utiliser le fait que Source.fromFile accepte un scala.io.Codec comme un paramètre implicite ( voir API ) :

def fromFile(name: String)(implicit codec: Codec): BufferedSource

ou, vous pouvez utiliser une chaîne de caractères comme deuxième paramètre, en spécifiant un java.nio.charset.Charset :

def fromFile(name: String, enc: String): BufferedSource

Ainsi, pour des données binaires de 8 bits, il peut être approprié d'utiliser quelque chose comme :

scala.io.Source.fromFile(fileName)(scala.io.Codec.ISO8859)
// or
scala.io.Source.fromFile(fileName, "ISO-8859-1")

et pour les données UTF-8, ce serait

scala.io.Source.fromFile(fileName)(scala.io.Codec.UTF8)
// or
scala.io.Source.fromFile(fileName, "UTF-8")

6voto

fengyun liu Points 31

La bibliothèque scala.io.Source est problématique, NE L'UTILISEZ PAS pour la lecture de fichiers binaires.

L'erreur peut être reproduite comme indiqué ici : https://github.com/liufengyun/scala-bug

Dans le fichier data.bin il contient le code hexadécimal 0xea qui est 11101010 en binaire et doit être converti en 234 en décimal.

El main.scala contient deux façons de lire le fichier :

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

Quand je cours scala main.scala les sorties du programme sont les suivantes :

Scala:205
Java:234

La bibliothèque Java génère une sortie correcte, alors que la bibliothèque Scala ne l'est pas.

11 votes

Si je règle l'encodage sur Source.fromFile("data.bin", "ISO8859-1") cela fonctionne bien.

6 votes

Peut-être que c'est utile, mais vraiment, ce n'est pas une réponse. Introduire un nouveau problème dans une réponse n'est pas constructif et appartient à un autre endroit.

5voto

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

3 votes

Ce n'est pas une solution valable. Extrait de la javadoc de 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X