Para leer, existe la abstracción útil Source
. ¿Cómo puedo escribir líneas en un archivo de texto?
Para leer, existe la abstracción útil Source
. ¿Cómo puedo escribir líneas en un archivo de texto?
Respuestas:
Edite 2019 (8 años después), Scala-IO no es muy activo, si es que tiene alguno, Li Haoyi sugiere su propia biblioteca lihaoyi/os-lib
, que presenta a continuación .
Junio de 2019, Xavier Guihot menciona en su respuesta a la biblioteca Using
, una utilidad para realizar la gestión automática de recursos.
Editar (septiembre de 2011): desde que Eduardo Costa pregunta por Scala2.9, y desde Rick-777 comenta que el historial de compromiso de scalax.IO es prácticamente inexistente desde mediados de 2009 ...
Scala-IO ha cambiado de lugar: vea su repositorio de GitHub , de Jesse Eichar (también en SO ):
El proyecto general Scala IO consta de algunos subproyectos para diferentes aspectos y extensiones de IO.
Hay dos componentes principales de Scala IO:
- Core : Core se ocupa principalmente de leer y escribir datos hacia y desde fuentes arbitrarias y sumideros. Los rasgos de piedra angular son
Input
,Output
ySeekable
que proporcionan la API central.
Otras clases de importancia sonResource
,ReadChars
yWriteChars
.- Archivo : el archivo es una API
File
(llamadaPath
) que se basa en una combinación del sistema de archivos Java 7 NIO y las API SBT PathFinder.
Path
yFileSystem
son los principales puntos de entrada a la API Scala IO File.
import scalax.io._
val output:Output = Resource.fromFile("someFile")
// Note: each write will open a new connection to file and
// each write is executed at the begining of the file,
// so in this case the last write will be the contents of the file.
// See Seekable for append and patching files
// Also See openOutput for performing several writes with a single connection
output.writeIntsAsBytes(1,2,3)
output.write("hello")(Codec.UTF8)
output.writeStrings(List("hello","world")," ")(Codec.UTF8)
Respuesta original (enero de 2011), con el antiguo lugar para scala-io:
Si no quiere esperar a Scala2.9, puede usar la biblioteca scala-incubator / scala-io .
(como se menciona en " ¿Por qué Scala Source no cierra el InputStream subyacente? ")
Ver las muestras
{ // several examples of writing data
import scalax.io.{
FileOps, Path, Codec, OpenOption}
// the codec must be defined either as a parameter of ops methods or as an implicit
implicit val codec = scalax.io.Codec.UTF8
val file: FileOps = Path ("file")
// write bytes
// By default the file write will replace
// an existing file with the new data
file.write (Array (1,2,3) map ( _.toByte))
// another option for write is openOptions which allows the caller
// to specify in detail how the write should take place
// the openOptions parameter takes a collections of OpenOptions objects
// which are filesystem specific in general but the standard options
// are defined in the OpenOption object
// in addition to the definition common collections are also defined
// WriteAppend for example is a List(Create, Append, Write)
file.write (List (1,2,3) map (_.toByte))
// write a string to the file
file.write("Hello my dear file")
// with all options (these are the default options explicitely declared)
file.write("Hello my dear file")(codec = Codec.UTF8)
// Convert several strings to the file
// same options apply as for write
file.writeStrings( "It costs" :: "one" :: "dollar" :: Nil)
// Now all options
file.writeStrings("It costs" :: "one" :: "dollar" :: Nil,
separator="||\n||")(codec = Codec.UTF8)
}
Esta es una de las características que faltan en Scala estándar que he encontrado tan útil que la agrego a mi biblioteca personal. (Probablemente también debería tener una biblioteca personal). El código es así:
def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) {
val p = new java.io.PrintWriter(f)
try { op(p) } finally { p.close() }
}
y se usa así:
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Source
(codificación predeterminada por defecto). Por supuesto, puede agregar, por ejemplo, un enc: Option[String] = None
parámetro después f
si considera que es una necesidad común.
Similar a la respuesta de Rex Kerr, pero más genérico. Primero uso una función auxiliar:
/**
* Used for reading/writing to database, files, etc.
* Code From the book "Beginning Scala"
* http://www.amazon.com/Beginning-Scala-David-Pollak/dp/1430219890
*/
def using[A <: {def close(): Unit}, B](param: A)(f: A => B): B =
try { f(param) } finally { param.close() }
Entonces uso esto como:
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
y
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
etc.
Una respuesta simple:
import java.io.File
import java.io.PrintWriter
def writeToFile(p: String, s: String): Unit = {
val pw = new PrintWriter(new File(p))
try pw.write(s) finally pw.close()
}
import
proviene?
Dando otra respuesta, porque mis ediciones de otras respuestas fueron rechazadas.
Esta es la respuesta más concisa y simple (similar a la de Garret Hall)
File("filename").writeAll("hello world")
Esto es similar a Jus12, pero sin la verbosidad y con el estilo de código correcto
def using[A <: {def close(): Unit}, B](resource: A)(f: A => B): B =
try f(resource) finally resource.close()
def writeToFile(path: String, data: String): Unit =
using(new FileWriter(path))(_.write(data))
def appendToFile(path: String, data: String): Unit =
using(new PrintWriter(new FileWriter(path, true)))(_.println(data))
Tenga en cuenta que NO necesita las llaves try finally
, ni las lambdas, y tenga en cuenta el uso de la sintaxis de marcador de posición. También tenga en cuenta una mejor denominación.
implemented
requisito previo. No puede usar el código que no está implementado. Quiero decir que debes decir cómo encontrarlo, ya que no está disponible por defecto y no es conocido.
Aquí hay una línea concisa usando la biblioteca del compilador Scala:
scala.tools.nsc.io.File("filename").writeAll("hello world")
Alternativamente, si desea utilizar las bibliotecas de Java, puede hacer este truco:
Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}
One liners para guardar / leer desde / hacia String
, usando java.nio
.
import java.nio.file.{Paths, Files, StandardOpenOption}
import java.nio.charset.{StandardCharsets}
import scala.collection.JavaConverters._
def write(filePath:String, contents:String) = {
Files.write(Paths.get(filePath), contents.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE)
}
def read(filePath:String):String = {
Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8).asScala.mkString
}
Esto no es adecuado para archivos grandes, pero hará el trabajo.
Algunos enlaces:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
write
copiará contents
a una nueva matriz de bytes en lugar de transmitirla al archivo, por lo tanto, en su punto máximo, usará el doble de memoria que contents
solo.
Desafortunadamente para la respuesta principal, Scala-IO está muerto. Si no le importa usar una dependencia de terceros, considere usar mi biblioteca OS-Lib . Esto hace que trabajar con archivos, rutas y el sistema de archivos sea muy fácil:
// Make sure working directory exists and is empty
val wd = os.pwd/"out"/"splash"
os.remove.all(wd)
os.makeDir.all(wd)
// Read/write files
os.write(wd/"file.txt", "hello")
os.read(wd/"file.txt") ==> "hello"
// Perform filesystem operations
os.copy(wd/"file.txt", wd/"copied.txt")
os.list(wd) ==> Seq(wd/"copied.txt", wd/"file.txt")
Tiene líneas simples para escribir en archivos , agregar archivos , sobrescribir archivos y muchas otras operaciones útiles / comunes
Una micro biblioteca que escribí: https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
o
file << "Hello" << "\n" << "World"
A partir Scala 2.13
, la biblioteca estándar proporciona una utilidad de gestión de recursos dedicados: Using
.
Se puede usar en este caso con recursos como PrintWriter
o BufferedWriter
que se extiende AutoCloseable
para escribir en un archivo y, sin importar qué, cierre el recurso después:
Por ejemplo, con java.io
api:
import scala.util.Using, java.io.{PrintWriter, File}
// val lines = List("hello", "world")
Using(new PrintWriter(new File("file.txt"))) {
writer => lines.foreach(writer.println)
}
O con java.nio
api:
import scala.util.Using, java.nio.file.{Files, Paths}, java.nio.charset.Charset
// val lines = List("hello", "world")
Using(Files.newBufferedWriter(Paths.get("file.txt"), Charset.forName("UTF-8"))) {
writer => lines.foreach(line => writer.write(line + "\n"))
}
ACTUALIZACIÓN en 2019 / Sep / 01:
finally
se tragaría el original Exception
arrojado try
si el finally
código arrojaba unException
Después de revisar todas estas respuestas sobre cómo escribir fácilmente un archivo en Scala, y algunas de ellas son bastante agradables, tuve tres problemas:
scala.util.Try
close
método se lleva a cabo en cada recurso dependiente en orden inverso - Nota: el cierre de los recursos dependientes en el orden inverso en particular en caso de un fallo es un requisito rara vez se entiende de la java.lang.AutoCloseable
especificación que tiende a generar errores muy perniciosos y difíciles de encontrar y fallas en el tiempo de ejecuciónAntes de comenzar, mi objetivo no es la concisión. Es para facilitar la comprensión de los principiantes Scala / FP, generalmente los que provienen de Java. Al final, juntaré todos los bits y luego aumentaré la concisión.
Primero, el using
método debe actualizarse para su uso Try
(nuevamente, la concisión no es el objetivo aquí). Será renombrado a tryUsingAutoCloseable
:
def tryUsingAutoCloseable[A <: AutoCloseable, R]
(instantiateAutoCloseable: () => A) //parameter list 1
(transfer: A => scala.util.Try[R]) //parameter list 2
: scala.util.Try[R] =
Try(instantiateAutoCloseable())
.flatMap(
autoCloseable => {
var optionExceptionTry: Option[Exception] = None
try
transfer(autoCloseable)
catch {
case exceptionTry: Exception =>
optionExceptionTry = Some(exceptionTry)
throw exceptionTry
}
finally
try
autoCloseable.close()
catch {
case exceptionFinally: Exception =>
optionExceptionTry match {
case Some(exceptionTry) =>
exceptionTry.addSuppressed(exceptionFinally)
case None =>
throw exceptionFinally
}
}
}
)
El comienzo del tryUsingAutoCloseable
método anterior puede ser confuso porque parece tener dos listas de parámetros en lugar de la lista de parámetros únicos habitual. Esto se llama curry. Y no entraré en detalles sobre cómo funciona el curry o dónde es útil ocasionalmente . Resulta que para este espacio problemático en particular, es la herramienta adecuada para el trabajo.
Luego, necesitamos crear un método, tryPrintToFile
que creará un (o sobrescribirá uno existente) File
y escribirá un List[String]
. Utiliza un FileWriter
que está encapsulado por un BufferedWriter
que a su vez está encapsulado por un PrintWriter
. Y para elevar el rendimiento, BufferedWriter
se define un tamaño de búfer predeterminado mucho mayor que el predeterminado para defaultBufferSize
, y se le asigna el valor 65536.
Aquí está el código (y nuevamente, la concisión no es el objetivo aquí):
val defaultBufferSize: Int = 65536
def tryPrintToFile(
lines: List[String],
location: java.io.File,
bufferSize: Int = defaultBufferSize
): scala.util.Try[Unit] = {
tryUsingAutoCloseable(() => new java.io.FileWriter(location)) { //this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
fileWriter =>
tryUsingAutoCloseable(() => new java.io.BufferedWriter(fileWriter, bufferSize)) { //this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
bufferedWriter =>
tryUsingAutoCloseable(() => new java.io.PrintWriter(bufferedWriter)) { //this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
printWriter =>
scala.util.Try(
lines.foreach(line => printWriter.println(line))
)
}
}
}
}
El tryPrintToFile
método anterior es útil porque toma un List[String]
como entrada y lo envía a File
. Ahora creemos un tryWriteToFile
método que tome a String
y lo escriba en a File
.
Aquí está el código (y te dejaré adivinar la prioridad de la concisión aquí):
def tryWriteToFile(
content: String,
location: java.io.File,
bufferSize: Int = defaultBufferSize
): scala.util.Try[Unit] = {
tryUsingAutoCloseable(() => new java.io.FileWriter(location)) { //this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
fileWriter =>
tryUsingAutoCloseable(() => new java.io.BufferedWriter(fileWriter, bufferSize)) { //this open brace is the start of the second curried parameter to the tryUsingAutoCloseable method
bufferedWriter =>
Try(bufferedWriter.write(content))
}
}
}
Finalmente, es útil poder obtener el contenido de a File
como a String
. Si bien scala.io.Source
proporciona un método conveniente para obtener fácilmente el contenido de a File
, el close
método se debe utilizar Source
para liberar la JVM subyacente y los identificadores del sistema de archivos. Si esto no se hace, entonces el recurso no se libera hasta que el JVM GC (Garbage Collector) pueda liberar la Source
instancia en sí. Y aun así, solo hay una garantía débil de JVM de que el finalize
método será llamado por el GC al close
recurso. Esto significa que es responsabilidad del cliente llamar explícitamente al close
método, de la misma manera que es responsabilidad de un cliente hacer un alto close
en una instancia dejava.lang.AutoCloseable
. Para esto, necesitamos una segunda definición del método de uso que maneja scala.io.Source
.
Aquí está el código para esto (todavía no es conciso):
def tryUsingSource[S <: scala.io.Source, R]
(instantiateSource: () => S)
(transfer: S => scala.util.Try[R])
: scala.util.Try[R] =
Try(instantiateSource())
.flatMap(
source => {
var optionExceptionTry: Option[Exception] = None
try
transfer(source)
catch {
case exceptionTry: Exception =>
optionExceptionTry = Some(exceptionTry)
throw exceptionTry
}
finally
try
source.close()
catch {
case exceptionFinally: Exception =>
optionExceptionTry match {
case Some(exceptionTry) =>
exceptionTry.addSuppressed(exceptionFinally)
case None =>
throw exceptionFinally
}
}
}
)
Y aquí hay un ejemplo de uso en un lector de archivos de transmisión de línea súper simple (actualmente utilizado para leer archivos delimitados por tabulaciones de la salida de la base de datos):
def tryProcessSource(
file: java.io.File
, parseLine: (String, Int) => List[String] = (line, index) => List(line)
, filterLine: (List[String], Int) => Boolean = (values, index) => true
, retainValues: (List[String], Int) => List[String] = (values, index) => values
, isFirstLineNotHeader: Boolean = false
): scala.util.Try[List[List[String]]] =
tryUsingSource(scala.io.Source.fromFile(file)) {
source =>
scala.util.Try(
( for {
(line, index) <-
source.getLines().buffered.zipWithIndex
values =
parseLine(line, index)
if (index == 0 && !isFirstLineNotHeader) || filterLine(values, index)
retainedValues =
retainValues(values, index)
} yield retainedValues
).toList //must explicitly use toList due to the source.close which will
//occur immediately following execution of this anonymous function
)
)
Se ha proporcionado una versión actualizada de la función anterior como respuesta a una pregunta diferente pero relacionada de StackOverflow .
Ahora, uniendo todo eso con las importaciones extraídas (lo que hace que sea mucho más fácil pegar en Scala Worksheet presente tanto en Eclipse ScalaIDE como en el complemento IntelliJ Scala para que sea más fácil volcar la salida al escritorio para examinarla más fácilmente con un editor de texto), así es como se ve el código (con mayor concisión):
import scala.io.Source
import scala.util.Try
import java.io.{BufferedWriter, FileWriter, File, PrintWriter}
val defaultBufferSize: Int = 65536
def tryUsingAutoCloseable[A <: AutoCloseable, R]
(instantiateAutoCloseable: () => A) //parameter list 1
(transfer: A => scala.util.Try[R]) //parameter list 2
: scala.util.Try[R] =
Try(instantiateAutoCloseable())
.flatMap(
autoCloseable => {
var optionExceptionTry: Option[Exception] = None
try
transfer(autoCloseable)
catch {
case exceptionTry: Exception =>
optionExceptionTry = Some(exceptionTry)
throw exceptionTry
}
finally
try
autoCloseable.close()
catch {
case exceptionFinally: Exception =>
optionExceptionTry match {
case Some(exceptionTry) =>
exceptionTry.addSuppressed(exceptionFinally)
case None =>
throw exceptionFinally
}
}
}
)
def tryUsingSource[S <: scala.io.Source, R]
(instantiateSource: () => S)
(transfer: S => scala.util.Try[R])
: scala.util.Try[R] =
Try(instantiateSource())
.flatMap(
source => {
var optionExceptionTry: Option[Exception] = None
try
transfer(source)
catch {
case exceptionTry: Exception =>
optionExceptionTry = Some(exceptionTry)
throw exceptionTry
}
finally
try
source.close()
catch {
case exceptionFinally: Exception =>
optionExceptionTry match {
case Some(exceptionTry) =>
exceptionTry.addSuppressed(exceptionFinally)
case None =>
throw exceptionFinally
}
}
}
)
def tryPrintToFile(
lines: List[String],
location: File,
bufferSize: Int = defaultBufferSize
): Try[Unit] =
tryUsingAutoCloseable(() => new FileWriter(location)) { fileWriter =>
tryUsingAutoCloseable(() => new BufferedWriter(fileWriter, bufferSize)) { bufferedWriter =>
tryUsingAutoCloseable(() => new PrintWriter(bufferedWriter)) { printWriter =>
Try(lines.foreach(line => printWriter.println(line)))
}
}
}
def tryWriteToFile(
content: String,
location: File,
bufferSize: Int = defaultBufferSize
): Try[Unit] =
tryUsingAutoCloseable(() => new FileWriter(location)) { fileWriter =>
tryUsingAutoCloseable(() => new BufferedWriter(fileWriter, bufferSize)) { bufferedWriter =>
Try(bufferedWriter.write(content))
}
}
def tryProcessSource(
file: File,
parseLine: (String, Int) => List[String] = (line, index) => List(line),
filterLine: (List[String], Int) => Boolean = (values, index) => true,
retainValues: (List[String], Int) => List[String] = (values, index) => values,
isFirstLineNotHeader: Boolean = false
): Try[List[List[String]]] =
tryUsingSource(() => Source.fromFile(file)) { source =>
Try(
( for {
(line, index) <- source.getLines().buffered.zipWithIndex
values = parseLine(line, index)
if (index == 0 && !isFirstLineNotHeader) || filterLine(values, index)
retainedValues = retainValues(values, index)
} yield retainedValues
).toList
)
}
Como un novato Scala / FP, he quemado muchas horas (en su mayoría frustración en la cabeza) ganando el conocimiento y las soluciones anteriores. Espero que esto ayude a otros novatos de Scala / FP a superar esta joroba de aprendizaje en particular más rápido.
try-catch-finally
. Aún amo tu pasión.
Aquí hay un ejemplo de cómo escribir algunas líneas en un archivo usando scalaz-stream .
import scalaz._
import scalaz.stream._
def writeLinesToFile(lines: Seq[String], file: String): Task[Unit] =
Process(lines: _*) // Process that enumerates the lines
.flatMap(Process(_, "\n")) // Add a newline after each line
.pipe(text.utf8Encode) // Encode as UTF-8
.to(io.fileChunkW(fileName)) // Buffered write to the file
.runLog[Task, Unit] // Get this computation as a Task
.map(_ => ()) // Discard the result
writeLinesToFile(Seq("one", "two"), "file.txt").run
Para superar a samthebest y a los contribuyentes antes que él, he mejorado el nombre y la concisión:
def using[A <: {def close() : Unit}, B](resource: A)(f: A => B): B =
try f(resource) finally resource.close()
def writeStringToFile(file: File, data: String, appending: Boolean = false) =
using(new FileWriter(file, appending))(_.write(data))
Either
para manejo de erroresdef write(destinationFile: Path, fileContent: String): Either[Exception, Path] =
write(destinationFile, fileContent.getBytes(StandardCharsets.UTF_8))
def write(destinationFile: Path, fileContent: Array[Byte]): Either[Exception, Path] =
try {
Files.createDirectories(destinationFile.getParent)
// Return the path to the destinationFile if the write is successful
Right(Files.write(destinationFile, fileContent))
} catch {
case exception: Exception => Left(exception)
}
val filePath = Paths.get("./testDir/file.txt")
write(filePath , "A test") match {
case Right(pathToWrittenFile) => println(s"Successfully wrote to $pathToWrittenFile")
case Left(exception) => println(s"Could not write to $filePath. Exception: $exception")
}
Actualización 2019:
Resumen: Java NIO (o NIO.2 para asíncrono) sigue siendo la solución de procesamiento de archivos más completa compatible con Scala. El siguiente código crea y escribe texto en un nuevo archivo:
import java.io.{BufferedOutputStream, OutputStream}
import java.nio.file.{Files, Paths}
val testFile1 = Paths.get("yourNewFile.txt")
val s1 = "text to insert in file".getBytes()
val out1: OutputStream = new BufferedOutputStream(
Files.newOutputStream(testFile1))
try {
out1.write(s1, 0, s1.length)
} catch {
case _ => println("Exception thrown during file writing")
} finally {
out1.close()
}
Path
objeto con tu nombre de archivo elegidoOutputStream
write
función de su flujo de salidaSimilar a esta respuesta , aquí hay un ejemplo con fs2
(versión 1.0.4):
import cats.effect._
import fs2._
import fs2.io
import java.nio.file._
import scala.concurrent.ExecutionContext
import scala.language.higherKinds
import cats.syntax.functor._
object ScalaApp extends IOApp {
def write[T[_]](p: Path, s: String)
(implicit F: ConcurrentEffect[T], cs: ContextShift[T]): T[Unit] = {
Stream(s)
.covary[T]
.through(text.utf8Encode)
.through(
io.file.writeAll(
p,
scala.concurrent.ExecutionContext.global,
Seq(StandardOpenOption.CREATE)
)
)
.compile
.drain
}
def run(args: List[String]): IO[ExitCode] = {
implicit val executionContext: ExecutionContext =
scala.concurrent.ExecutionContext.Implicits.global
implicit val contextShift: ContextShift[IO] =
IO.contextShift(executionContext)
val outputFile: Path = Paths.get("output.txt")
write[IO](outputFile, "Hello world\n").as(ExitCode.Success)
}
}
Si de todos modos tiene Akka Streams en su proyecto, proporciona una línea:
def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}