361 votes

Lire un fichier entier en Scala ?

Quelle est la manière simple et canonique de lire un fichier entier en mémoire en Scala ? (Idéalement, avec un contrôle sur l'encodage des caractères).

Le mieux que je puisse faire est :

scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)

ou suis-je censé utiliser une des Les idiomes horribles de Java dont le meilleur (sans utiliser de bibliothèque externe) semble être :

import java.util.Scanner
import java.io.File
new Scanner(new File("file.txt")).useDelimiter("\\Z").next()

À la lecture des discussions sur les listes de diffusion, je ne suis pas sûr que scala.io.Source soit censée être la bibliothèque d'E/S canonique. Je ne comprends pas exactement quel est son objectif.

... Je voudrais quelque chose de très simple et facile à retenir. Par exemple, dans ces langues, il est très difficile d'oublier l'idiome ...

Ruby    open("file.txt").read
Ruby    File.read("file.txt")
Python  open("file.txt").read()

12 votes

Java n'est pas si mal si vous connaissez les bons outils. import org.apache.commons.io.FileUtils ; FileUtils.readFileToString(new File("file.txt", "UTF-8")

25 votes

Ce commentaire ne tient pas compte de la conception du langage. Tout langage qui dispose d'une fonction de bibliothèque simple pour exactement l'opération que vous voulez effectuer est donc aussi bon que sa syntaxe d'invocation de fonction. Si l'on disposait d'une bibliothèque infinie et 100% mémorisée, tous les programmes seraient implémentés avec un seul appel de fonction. Un langage de programmation est bon lorsqu'il nécessite l'existence d'un nombre réduit de composants préfabriqués afin d'obtenir un résultat spécifique.

0 votes

Je crains que "étant donné une bibliothèque infinie et 100% mémorisée" ne soit pas une prémisse pour un argument rationnel ! Les langages de programmation sont pour les humains, et idéalement devraient contenir juste les abstractions nécessaires pour coller les choses ensemble.

484voto

Daniel C. Sobral Points 159554
val lines = scala.io.Source.fromFile("file.txt").mkString

D'ailleurs, " scala. " n'est pas vraiment nécessaire, car il est toujours dans le champ d'application de toute façon, et vous pouvez, bien sûr, importer le contenu de io, entièrement ou partiellement, et éviter d'avoir à faire précéder "io." aussi.

Ce qui précède laisse cependant le dossier ouvert. Pour éviter tout problème, vous devriez le fermer comme ceci :

val source = scala.io.Source.fromFile("file.txt")
val lines = try source.mkString finally source.close()

Un autre problème avec le code ci-dessus est qu'il est horriblement lent en raison de sa nature d'implémentation. Pour les gros fichiers, il faut utiliser :

source.getLines mkString "\n"

0 votes

Ah, c'est définitivement mieux que reduceLeft( + ).

52 votes

J'arrive trop tard à la fête, mais je détesterais que les gens ne sachent pas qu'ils peuvent faire "io.File("/etc/passwd").slurp" dans trunk.

6 votes

Je détesterais que Scala 2.8 ait une méthode appelée " slurp "mais il semble que je sois coincé avec ça de toute façon.

64voto

Daniel Spiewak Points 30706

Pour compléter la solution de Daniel, vous pouvez raccourcir considérablement les choses en insérant l'importation suivante dans tout fichier nécessitant une manipulation :

import scala.io.Source._

Avec cela, vous pouvez maintenant faire :

val lines = fromFile("file.txt").getLines

Je me méfierais de la lecture d'un fichier entier dans un seul String . C'est une très mauvaise habitude, qui vous piquera plus tôt et plus fort que vous ne le pensez. Le site getLines retourne une valeur de type Iterator[String] . Il s'agit en fait d'un curseur paresseux dans le fichier, qui vous permet d'examiner uniquement les données dont vous avez besoin sans risquer de saturer la mémoire.

Oh, et pour répondre à votre question implicite sur Source : oui, c'est la bibliothèque d'E/S canonique. La plupart du code finit par utiliser java.io en raison de son interface de plus bas niveau et de sa meilleure compatibilité avec les frameworks existants, mais tout code qui a le choix devrait utiliser Source notamment pour la manipulation simple de fichiers.

0 votes

OK. Il y a une histoire pour mon impression négative de la Source : Je me suis déjà trouvé dans une situation différente de celle d'aujourd'hui, où j'avais un très gros fichier qui ne tenait pas en mémoire. L'utilisation de Source a fait planter le programme ; il s'est avéré qu'il essayait de lire tout le fichier en même temps.

7 votes

Source n'est pas censé lire l'intégralité du fichier en mémoire. Si vous utilisez toList après getLines, ou toute autre méthode qui produira une collection, alors vous obtenez tout en mémoire. Maintenant, Source est un pirater Il ne s'agit pas d'une bibliothèque soigneusement conçue, mais d'un outil destiné à faire le travail. Elle sera améliorée dans Scala 2.8, mais la communauté Scala a certainement la possibilité de participer activement à la définition d'une bonne API d'entrée/sortie.

37voto

Walter Chang Points 7041
// for file with utf-8 encoding
val lines = scala.io.Source.fromFile("file.txt", "utf-8").getLines.mkString

6 votes

L'ajout de "getLines" à la réponse originale supprimera toutes les nouvelles lignes. Ce devrait être "Source.fromFile("fichier.txt", "utf-8").mkString".

11 votes

Voir également mon commentaire dans la réponse de Daniel C. Sobral - cette utilisation ne fermera pas l'instance Source, de sorte que Scala peut conserver un verrou sur le fichier.

25voto

extempore Points 8016

(EDIT : Cela ne fonctionne pas dans scala 2.9 et peut-être pas 2.8 non plus)

Utilisez le tronc :

scala> io.File("/etc/passwd").slurp
res0: String = 
##
# User Database
# 
... etc

15 votes

" slurp " ? Avons-nous vraiment abandonné les noms évidents et intuitifs ? Le problème avec slurp c'est que cela peut avoir un sens après coup, pour quelqu'un dont l'anglais est la première langue, du moins, mais que vous n'y auriez jamais pensé au départ !

5 votes

Je suis tombé par hasard sur cette question/réponse. File n'est plus dans la 2.8.0, n'est-ce pas ?

3 votes

Vous pouvez toujours vous faufiler dans scala.tools.nsc.io.File, mais je suppose que cet emplacement pourrait changer à l'avenir, alors utilisez-le à vos risques et périls ;-) Oh, et permettez-moi d'intervenir pour dire à quel point je déteste le nom "slurp".

7voto

Ikai Lan Points 1574

On m'a dit que Source.fromFile était problématique. Personnellement, j'ai eu des problèmes pour ouvrir de gros fichiers avec Source.fromFile et j'ai dû recourir à Java InputStreams.

Une autre solution intéressante est l'utilisation de scalax. Voici un exemple de code bien commenté qui ouvre un fichier journal en utilisant ManagedResource pour ouvrir un fichier avec des aides scalax : http://pastie.org/pastes/420714

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