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, Outputy Seekableque proporcionan la API central.
Otras clases de importancia son Resource, ReadCharsy WriteChars.
Archivo : el archivo es una API File(llamada Path) que se basa en una combinación del sistema de archivos Java 7 NIO y las API SBT PathFinder. Pathy FileSystemson 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:
{// several examples of writing dataimport scalax.io.{FileOps,Path,Codec,OpenOption}// the codec must be defined either as a parameter of ops methods or as an implicitimplicitval 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)}
El proyecto scalax parece muerto (sin compromisos desde junio de 2009). ¿Es esto correcto? scalax commit history
Rick-777
@Eduardo: He completado mi respuesta con el nuevo lugar para la biblioteca scala-io (que se ha actualizado para Scala2.9: github.com/jesseeichar/scala-io/issues/20 )
VonC
10
¿Es esta realmente la sugerencia actual para Scala 2.10? Utilice Scala IO? ¿Todavía no hay nada en el núcleo de Scala?
Phil
2
Nunca he usado scalax.io, pero a juzgar por estas líneas de ejemplo, parece que su diseño de API es bastante malo. La combinación de métodos para caracteres y datos binarios en una interfaz tiene poco sentido y muy probablemente conducirá a errores de codificación que son difíciles de encontrar. El diseño de java.io (Reader / Writer vs. InputStream / OutputStream) parece mucho mejor.
jcsahnwaldt Restablece a Monica el
211
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(newFile("example.txt")){ p =>
data.foreach(p.println)}
new java.io.PrintWriter () usa la codificación predeterminada de la plataforma, lo que probablemente significa que el archivo de resultados no es muy portátil. Por ejemplo, si desea producir un archivo que luego puede enviar por correo electrónico, probablemente debería usar el constructor PrintWriter que le permite especificar una codificación.
jcsahnwaldt Restablece a Monica el
@JonaChristopherSahnwaldt: claro, en casos especiales es posible que desee especificar la codificación. El valor predeterminado para la plataforma es el valor predeterminado más sensible en promedio. Igual que con Source(codificación predeterminada por defecto). Por supuesto, puede agregar, por ejemplo, un enc: Option[String] = Noneparámetro después fsi considera que es una necesidad común.
Rex Kerr
66
@RexKerr - No estoy de acuerdo. Se debe especificar la codificación en casi todos los casos. La mayoría de los errores de codificación que encuentro ocurren porque las personas no entienden o no piensan en la codificación. Utilizan el valor predeterminado y ni siquiera lo saben porque demasiadas API les permiten salirse con la suya. Hoy en día, el valor predeterminado más sensato probablemente sería UTF-8. Quizás solo trabajas con inglés y otros idiomas que se pueden escribir en ASCII. Eres afortunado. Vivo en Alemania y tuve que arreglar más diéresis rotas de las que me gustaría recordar.
jcsahnwaldt Restablece a Monica el
3
@JonaChristopherSahnwaldt: esta es una razón para tener una codificación predeterminada sensata, no para obligar a todos a especificarla todo el tiempo. Pero si estás en una Mac y tus archivos escritos por Java son engullidos porque no están codificados en Mac OS Roman, no estoy seguro de que esté haciendo más bien que mal. Creo que es culpa de las plataformas que no hayan acordado un juego de caracteres. Como desarrollador individual, escribir una cadena realmente no va a resolver el problema. (Todos los desarrolladores que estén de acuerdo con UTF-8 lo harían, pero eso puede entrar por defecto).
Rex Kerr
@JonaChristopherSahnwaldt +10 por arreglar toda la diéresis rota. ¿No puedes usar un martillo, tal vez un perforador? ¿O ya son agujeros que necesitan relleno, tal vez este tipo pueda ayudar a youtube.com/watch?v=E-eBBzWEpwE Pero en serio, la influencia de ASCII es tan dañina en el mundo, de acuerdo que debería especificarse, y por defecto como UTF- 8
Davos
50
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 (newFileWriter(fileName)){
fileWriter => fileWriter.write(data)}
y
def appendToFile(fileName:String, textData:String)=
using (newFileWriter(fileName,true)){
fileWriter => using (newPrintWriter(fileWriter)){
printWriter => printWriter.println(textData)}}
No me malinterpreten, me gusta su código y es muy educativo, pero cuanto más veo tales construcciones para problemas simples, más me recuerda el viejo chiste "hello world": ariel.com.au/jokes/The_Evolution_of_a_Programmer .html :-) (+1 voto de mi parte).
greenoldman
44
Si estás escribiendo frases sencillas, nada importa. Si está escribiendo programas importantes (grandes con una necesidad continua de mantenimiento y evolución), este tipo de pensamiento conduce al tipo más rápido y pernicioso de degradación de la calidad del software.
Randall Schulz
3
No todos van a tener "ojos scala" hasta cierto nivel de práctica. Es divertido ver que este ejemplo de código proviene de Scala "Principiante"
asyncwait
asyncwait "begin" scala ... el título más irónico de la historia, nota: tengo el libro ... y justo ahora estoy empezando a entenderlo ... Supongo que estaba un paso antes de "principiante" jajaja: D ........
user1050817
1
El problema es menos los trucos Scala aquí, pero la verbosidad y el mal estilo. He editado esto a mucho más legible. Después de mi refactorización son solo 4 líneas (bueno, 4 con longitudes de línea IDE, utilicé 6 aquí para caber en la pantalla). En mi humilde opinión, ahora es una muy buena respuesta.
@samthebest, ¿podría agregar las bibliotecas de donde importproviene?
Daniel
1
A partir de java 7, use java.nio.file en su lugar: def writeToFile (file: String, stringToWrite: String): Unit = {val writer = Files.newBufferedWriter (Paths.get (archivo)) intente writer.write (stringToWrite) finalmente writer.close ()}
E Shindler
20
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(newFileWriter(path))(_.write(data))def appendToFile(path:String, data:String):Unit=
using(newPrintWriter(newFileWriter(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.
Lo sentimos, pero su código es imaginable, no cumple con el implementedrequisito 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.
Val
15
Aquí hay una línea concisa usando la biblioteca del compilador Scala:
¿Por qué no es esto adecuado para archivos grandes?
Chetan Bhasin
2
@ChetanBhasin Probablemente porque writecopiará contentsa 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 contentssolo.
Daniel Werner el
10
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 emptyval 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")
Aquí también: esta pregunta es uno de los principales éxitos al buscar en Google cómo escribir un archivo con scala. Ahora que su proyecto ha crecido, ¿es posible que desee ampliar un poco su respuesta?
asac
6
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 PrintWritero BufferedWriterque se extiende AutoCloseablepara escribir en un archivo y, sin importar qué, cierre el recurso después:
Comenzando con Scala 2.13, prefiera usar scala.util.
Se corrigió el error por el que finallyse tragaría el original Exceptionarrojado trysi el finallycó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:
En la respuesta de Jus12 , el uso de curry para usar el método auxiliar no es obvio para los principiantes de Scala / FP
Necesita encapsular errores de nivel inferior con scala.util.Try
Necesita mostrar los desarrolladores de Java nuevas a Scala / FP cómo adecuadamente nido dependientes de los recursos por lo que el closemé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.AutoCloseableespecificación que tiende a generar errores muy perniciosos y difíciles de encontrar y fallas en el tiempo de ejecución
Antes 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 usingmé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]=Nonetry
transfer(autoCloseable)catch{case exceptionTry:Exception=>
optionExceptionTry =Some(exceptionTry)throw exceptionTry
}finallytry
autoCloseable.close()catch{case exceptionFinally:Exception=>
optionExceptionTry match{caseSome(exceptionTry)=>
exceptionTry.addSuppressed(exceptionFinally)caseNone=>throw exceptionFinally
}}})
El comienzo del tryUsingAutoCloseablemé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, tryPrintToFileque creará un (o sobrescribirá uno existente) Filey escribirá un List[String]. Utiliza un FileWriterque está encapsulado por un BufferedWriterque a su vez está encapsulado por un PrintWriter. Y para elevar el rendimiento, BufferedWriterse 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=65536def 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 tryPrintToFilemétodo anterior es útil porque toma un List[String]como entrada y lo envía a File. Ahora creemos un tryWriteToFilemétodo que tome a Stringy 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 Filecomo a String. Si bien scala.io.Sourceproporciona un método conveniente para obtener fácilmente el contenido de a File, el closemétodo se debe utilizar Sourcepara 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 Sourceinstancia en sí. Y aun así, solo hay una garantía débil de JVM de que el finalizemétodo será llamado por el GC al closerecurso. Esto significa que es responsabilidad del cliente llamar explícitamente al closemétodo, de la misma manera que es responsabilidad de un cliente hacer un alto closeen 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):
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))
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):
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.
Increíble actualización. El único problema es que ahora tiene como 100 líneas de código que podrían reemplazarse try-catch-finally. Aún amo tu pasión.
Observador
1
@Observer Yo afirmaría que es una declaración inexacta. El patrón que describo en realidad está reduciendo la cantidad de repeticiones que debe escribir un cliente para garantizar el manejo adecuado del cierre de AutoCloseables al tiempo que habilita el patrón de FP idiomático Scala de usar scala.util. Try. Si intentas lograr los mismos efectos que yo escribiendo manualmente los bloques try / catch / finally, creo que encontrarás que terminas con un poco más de lo que imaginas. Por lo tanto, hay un valor de legibilidad significativo al empujar todo el repetitivo a las 100 líneas de la función Scala.
chaotic3quilibrium
1
Lo siento si eso sonó ofensivo de alguna manera. Aún así, mi punto es que no hay necesidad de tal cantidad de código, porque lo mismo podría lograrse mediante un enfoque no funcional con mucha más simplicidad. Personalmente, escribiría try-finally con algunas verificaciones adicionales. Es solo más corto. Si quisiera usar envoltorios, ApacheUtils están ahí para usar todo el trabajo sucio. Además, todos los lectores / escritores estándar cierran las secuencias subyacentes, por lo que no se necesita su envoltura múltiple. PD: He cambiado mi voto de menos uno a más uno para apoyar sus esfuerzos. Entonces, por favor, no sospeches de mí con malas intenciones.
Observador
No se ofende.
chaotic3quilibrium
1
Entiendo tu punto de vista. Gracias por la discusión, tengo que pensarlo un poco. ¡Que tengas un buen día!
Observador
3
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
def 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 successfulRight(Files.write(destinationFile, fileContent))}catch{case exception:Exception=>Left(exception)}
Uso
val filePath =Paths.get("./testDir/file.txt")
write(filePath ,"A test")match{caseRight(pathToWrittenFile)=> println(s"Successfully wrote to $pathToWrittenFile")caseLeft(exception)=> println(s"Could not write to $filePath. Exception: $exception")}
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=newBufferedOutputStream(Files.newOutputStream(testFile1))try{
out1.write(s1,0, s1.length)}catch{case _ => println("Exception thrown during file writing")}finally{
out1.close()}
Importar bibliotecas Java: IO y NIO
Crea un Pathobjeto con tu nombre de archivo elegido
Convierta el texto que desea insertar en un archivo en una matriz de bytes
Obtenga su archivo como una secuencia: OutputStream
Pase su matriz de bytes a la writefunción de su flujo de salida
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 ):
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
fuente
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í:
y se usa así:
fuente
Source
(codificación predeterminada por defecto). Por supuesto, puede agregar, por ejemplo, unenc: Option[String] = None
parámetro despuésf
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:
Entonces uso esto como:
y
etc.
fuente
Una respuesta simple:
fuente
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)
Esto es similar a Jus12, pero sin la verbosidad y con el estilo de código correcto
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.fuente
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:
Alternativamente, si desea utilizar las bibliotecas de Java, puede hacer este truco:
fuente
scala.tools.nsc.io.File("/tmp/myFile.txt")
trabaja en Scala 2.11.8.One liners para guardar / leer desde / hacia
String
, usandojava.nio
.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
fuente
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 quecontents
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:
Tiene líneas simples para escribir en archivos , agregar archivos , sobrescribir archivos y muchas otras operaciones útiles / comunes
fuente
Una micro biblioteca que escribí: https://github.com/pathikrit/better-files
o
fuente
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
oBufferedWriter
que se extiendeAutoCloseable
para escribir en un archivo y, sin importar qué, cierre el recurso después:Por ejemplo, con
java.io
api:O con
java.nio
api:fuente
ACTUALIZACIÓN en 2019 / Sep / 01:
finally
se tragaría el originalException
arrojadotry
si elfinally
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 lajava.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 usoTry
(nuevamente, la concisión no es el objetivo aquí). Será renombrado atryUsingAutoCloseable
: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á unList[String]
. Utiliza unFileWriter
que está encapsulado por unBufferedWriter
que a su vez está encapsulado por unPrintWriter
. Y para elevar el rendimiento,BufferedWriter
se define un tamaño de búfer predeterminado mucho mayor que el predeterminado paradefaultBufferSize
, y se le asigna el valor 65536.Aquí está el código (y nuevamente, la concisión no es el objetivo aquí):
El
tryPrintToFile
método anterior es útil porque toma unList[String]
como entrada y lo envía aFile
. Ahora creemos untryWriteToFile
método que tome aString
y lo escriba en aFile
.Aquí está el código (y te dejaré adivinar la prioridad de la concisión aquí):
Finalmente, es útil poder obtener el contenido de a
File
como aString
. Si bienscala.io.Source
proporciona un método conveniente para obtener fácilmente el contenido de aFile
, elclose
método se debe utilizarSource
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 laSource
instancia en sí. Y aun así, solo hay una garantía débil de JVM de que elfinalize
método será llamado por el GC alclose
recurso. Esto significa que es responsabilidad del cliente llamar explícitamente alclose
método, de la misma manera que es responsabilidad de un cliente hacer un altoclose
en una instancia dejava.lang.AutoCloseable
. Para esto, necesitamos una segunda definición del método de uso que manejascala.io.Source
.Aquí está el código para esto (todavía no es conciso):
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):
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):
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.
fuente
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 .
fuente
Para superar a samthebest y a los contribuyentes antes que él, he mejorado el nombre y la concisión:
fuente
Sin dependencias, con manejo de errores.
Either
para manejo de erroresCódigo
Uso
fuente
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:
Path
objeto con tu nombre de archivo elegidoOutputStream
write
función de su flujo de salidafuente
Similar a esta respuesta , aquí hay un ejemplo con
fs2
(versión 1.0.4):fuente
Esta línea ayuda a escribir un archivo desde una matriz o cadena.
fuente
Si de todos modos tiene Akka Streams en su proyecto, proporciona una línea:
Documentos de Akka> Streaming File IO
fuente