Para leitura, existe a abstração útil Source
. Como escrever linhas em um arquivo de texto?
Para leitura, existe a abstração útil Source
. Como escrever linhas em um arquivo de texto?
Respostas:
Edit 2019 (8 years later), Scala-IO não sendo muito ativo, se houver, Li Haoyi sugere sua própria biblioteca lihaoyi/os-lib
, que ele apresenta abaixo .
Em junho de 2019, Xavier Guihot menciona em sua resposta a biblioteca Using
, um utilitário para executar o gerenciamento automático de recursos.
Editar (setembro de 2011): desde que Eduardo Costa pergunta sobre o Scala2.9, e desde que Rick-777 comenta que o scalax.IO confirma o histórico praticamente inexistente desde meados de 2009 ...
O Scala-IO mudou de lugar: veja seu repositório GitHub , de Jesse Eichar (também no SO ):
O projeto guarda-chuva Scala IO consiste em alguns subprojetos para diferentes aspectos e extensões de IO.
Existem dois componentes principais do Scala IO:
- Núcleo - O núcleo lida principalmente com a leitura e gravação de dados de e para fontes e sumidouros arbitrários. Os traços canto de pedra são
Input
,Output
eSeekable
que fornecem a API núcleo.
Outras classes de importância sãoResource
,ReadChars
eWriteChars
.- File - File é uma API
File
(chamadaPath
) que é baseada em uma combinação do sistema de arquivos Java 7 NIO e APIs do SBT PathFinder.
Path
eFileSystem
são os principais pontos de entrada na API do 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)
Resposta original (janeiro de 2011), com o antigo local para scala-io:
Se você não quiser esperar pelo Scala2.9, poderá usar a biblioteca scala-incubator / scala-io .
(como mencionado em " Por que o Scala Source não fecha o InputStream subjacente? ")
Veja as amostras
{ // 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)
}
Esse é um dos recursos ausentes do Scala padrão que achei tão útil que o adicionei à minha biblioteca pessoal. (Você provavelmente também deve ter uma biblioteca pessoal.) O código é assim:
def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) {
val p = new java.io.PrintWriter(f)
try { op(p) } finally { p.close() }
}
e é usado assim:
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Source
(codificação padrão por padrão). Obviamente, você pode adicionar, por exemplo, um enc: Option[String] = None
parâmetro depois f
se achar isso uma necessidade comum.
Semelhante à resposta de Rex Kerr, mas mais genérica. Primeiro eu uso uma função 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() }
Então eu uso isso como:
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
e
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
etc.
Uma resposta simples:
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
de onde?
Dando outra resposta, porque minhas edições de outras respostas foram rejeitadas.
Esta é a resposta mais concisa e simples (semelhante à de Garret Hall)
File("filename").writeAll("hello world")
É semelhante ao Jus12, mas sem a verbosidade e com o estilo de código correto
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))
Observe que você NÃO precisa de chaves try finally
, nem lambdas, e observe o uso da sintaxe do espaço reservado. Observe também uma melhor nomeação.
implemented
pré - requisitos. Você não pode usar o código que não está implementado. Quero dizer que você deve dizer como encontrá-lo, pois ele não está disponível por padrão e não é conhecido.
Aqui está uma linha concisa usando a biblioteca de compiladores Scala:
scala.tools.nsc.io.File("filename").writeAll("hello world")
Como alternativa, se você quiser usar as bibliotecas Java, poderá fazer isso:
Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}
Forros um para salvar / ler de / para 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
}
Isso não é adequado para arquivos grandes, mas fará o trabalho.
Alguns links:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
write
copiará contents
para uma nova matriz de bytes em vez de transmiti-la para o arquivo, assim, no auge, usando duas vezes mais memória do que contents
sozinha.
Infelizmente para a resposta principal, o Scala-IO está morto. Se você não se importa em usar uma dependência de terceiros, considere usar minha biblioteca OS-Lib . Isso facilita muito o trabalho com arquivos, caminhos e sistema de arquivos:
// 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")
Possui uma linha para gravar arquivos , anexar arquivos , sobrescrever arquivos e muitas outras operações úteis / comuns
Uma micro biblioteca que escrevi: https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
ou
file << "Hello" << "\n" << "World"
Começando Scala 2.13
, a biblioteca padrão fornece um utilitário de gestão de recursos dedicado: Using
.
Ele pode ser usado nesse caso com recursos como PrintWriter
ou BufferedWriter
que se estendem AutoCloseable
para gravar em um arquivo e, não importa o quê, feche o recurso posteriormente:
Por exemplo, com 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)
}
Ou com 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"))
}
ATUALIZAÇÃO em 2019 / Sep / 01:
finally
que engoliria o original Exception
jogado try
se o finally
código lançasse umException
Depois de revisar todas essas respostas sobre como escrever facilmente um arquivo no Scala, e algumas delas são bastante legais, tive três problemas:
scala.util.Try
close
método seja executado em cada recurso dependente na ordem inversa - Nota: fechar recursos dependentes na ordem inversa ESPECIALMENTE EM CASO DE FALHA é um requisito raramente compreendido a java.lang.AutoCloseable
especificação que tende a levar a erros muito perniciosos e difíceis de encontrar e falhas no tempo de execuçãoAntes de começar, meu objetivo não é concisão. É para facilitar um entendimento mais fácil para iniciantes do Scala / FP, geralmente aqueles provenientes de Java. No final, reunirei todos os bits e aumentarei a concisão.
Primeiro, o using
método precisa ser atualizado para uso Try
(novamente, concisão não é o objetivo aqui). Ele será renomeado para 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
}
}
}
)
O início do tryUsingAutoCloseable
método acima pode ser confuso porque parece ter duas listas de parâmetros em vez da lista de parâmetros únicos habitual. Isso é chamado de curry. E não entrarei em detalhes como o curry funciona ou onde é ocasionalmente útil. Acontece que, para esse espaço problemático específico, é a ferramenta certa para o trabalho.
Em seguida, precisamos criar o método,, tryPrintToFile
que criará um (ou substituirá um existente) File
e gravará um List[String]
. Ele usa um FileWriter
que é encapsulado por um BufferedWriter
que, por sua vez, é encapsulado por a PrintWriter
. E para elevar o desempenho, BufferedWriter
é definido um tamanho de buffer padrão muito maior que o padrão para defaultBufferSize
, e atribuído o valor 65536.
Aqui está o código (e novamente, concisão não é o objetivo aqui):
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))
)
}
}
}
}
O tryPrintToFile
método acima é útil, pois recebe uma List[String]
entrada como e envia para a File
. Vamos agora criar um tryWriteToFile
método que pega a String
e grava em a File
.
Aqui está o código (e eu vou deixar você adivinhar a prioridade da concisão aqui):
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, é útil poder buscar o conteúdo de a File
como a String
. Embora scala.io.Source
forneça um método conveniente para obter facilmente o conteúdo de a File
, o close
método deve ser usado Source
para liberar os identificadores subjacentes da JVM e do sistema de arquivos. Se isso não for feito, o recurso não será liberado até que o JVM GC (Garbage Collector) saia para liberar a Source
instância em si. E mesmo assim, há apenas uma garantia fraca da JVM de que o finalize
método será chamado pelo GC para close
o recurso. Isso significa que é responsabilidade do cliente chamar explicitamente o close
método, da mesma forma que é responsabilidade de um cliente contar close
com uma instância dejava.lang.AutoCloseable
. Para isso, precisamos de uma segunda definição do método using que manipula scala.io.Source
.
Aqui está o código para isso (ainda não sendo 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
}
}
}
)
E aqui está um exemplo de uso dele em um leitor de arquivos de streaming de linha super simples (atualmente usando para ler arquivos delimitados por tabulações da saída do banco de dados):
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
)
)
Uma versão atualizada da função acima foi fornecida como resposta a uma pergunta StackOverflow diferente, mas relacionada .
Agora, reunindo tudo isso com as importações extraídas (facilitando a colagem na planilha Scala presente no plug-in Eclipse ScalaIDE e IntelliJ Scala para facilitar o despejo de saída na área de trabalho para ser examinado mais facilmente com um editor de texto), é assim que o código se parece (com maior concisão):
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 um novato no Scala / FP, eu queimei muitas horas (principalmente na frustração de arranhar a cabeça), ganhando o conhecimento e as soluções acima. Espero que isso ajude outros iniciantes do Scala / FP a superar esse problema de aprendizado mais rápido.
try-catch-finally
. Ainda amo sua paixão.
Aqui está um exemplo de gravação de algumas linhas em um arquivo usando o 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 o melhor e os colaboradores antes dele, melhorei a nomeação e a concisão:
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 tratamento de errosdef 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")
}
Atualização de 2019:
Resumo - O Java NIO (ou NIO.2 para assíncrono) ainda é a solução de processamento de arquivos mais abrangente suportada no Scala. O código a seguir cria e grava algum texto em um novo arquivo:
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 com o nome do arquivo escolhidoOutputStream
write
função do fluxo de saídaSemelhante a esta resposta , aqui está um exemplo com fs2
(versão 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)
}
}
Se você tem o Akka Streams no seu projeto, ele fornece uma única linha:
def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}
Documentos> Streaming IO do arquivo