Untuk membaca, ada abstraksi yang bermanfaat Source
. Bagaimana saya bisa menulis baris ke file teks?
Untuk membaca, ada abstraksi yang bermanfaat Source
. Bagaimana saya bisa menulis baris ke file teks?
Jawaban:
Sunting 2019 (8 tahun kemudian), Scala-IO menjadi sangat tidak aktif, jika ada, Li Haoyi menyarankan perpustakaannya sendiri lihaoyi/os-lib
, yang dia sajikan di bawah ini .
Juni 2019, Xavier Guihot menyebutkan dalam jawabannya perpustakaan Using
, sebuah utilitas untuk melakukan manajemen sumber daya otomatis.
Sunting (September 2011): sejak Eduardo Costa bertanya tentang Scala2.9, dan sejak Rick-777 berkomentar bahwa scalax.IO mencatat sejarah hampir tidak ada sejak pertengahan 2009 ...
Scala-IO telah berubah tempat: lihat repo GitHub -nya, dari Jesse Eichar (juga di SO ):
Proyek payung IO Scala terdiri dari beberapa sub proyek untuk berbagai aspek dan ekstensi IO.
Ada dua komponen utama Scala IO:
- Core - Core terutama berkaitan dengan Membaca dan menulis data ke dan dari sumber yang sewenang-wenang dan tenggelam. Ciri-ciri batu sudut adalah
Input
,Output
danSeekable
yang menyediakan API inti.
Kelas penting lainnya adalahResource
,ReadChars
danWriteChars
.- File - File adalah
File
(disebutPath
) API yang didasarkan pada kombinasi sistem file Java 7 NIO dan SBT PathFinder API.
Path
danFileSystem
merupakan titik masuk utama ke dalam Scala IO File API.
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)
Jawaban asli (Januari 2011), dengan tempat lama untuk scala-io:
Jika Anda tidak ingin menunggu Scala2.9, Anda dapat menggunakan perpustakaan scala-incubator / scala-io .
(seperti yang disebutkan dalam " Mengapa Sumber Scala tidak menutup InputStream yang mendasarinya? ")
Lihat sampel
{ // 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)
}
Ini adalah salah satu fitur yang hilang dari Scala standar yang saya temukan sangat berguna sehingga saya menambahkannya ke perpustakaan pribadi saya. (Anda mungkin harus memiliki perpustakaan pribadi juga.) Kode seperti ini:
def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) {
val p = new java.io.PrintWriter(f)
try { op(p) } finally { p.close() }
}
dan digunakan seperti ini:
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Source
(penyandian standar secara default). Anda tentu saja dapat menambahkan misalnya enc: Option[String] = None
parameter setelah f
jika Anda menemukan ini sebagai kebutuhan umum.
Serupa dengan jawaban oleh Rex Kerr, tetapi lebih umum. Pertama saya menggunakan fungsi pembantu:
/**
* 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() }
Maka saya menggunakan ini sebagai:
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
dan
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
dll.
Jawaban sederhana:
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
berasal?
Memberikan jawaban lain, karena hasil edit saya dari jawaban lain ditolak.
Ini adalah jawaban yang paling ringkas dan sederhana (mirip dengan Garret Hall)
File("filename").writeAll("hello world")
Ini mirip dengan Jus12, tetapi tanpa verbosity dan dengan gaya kode yang benar
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))
Perhatikan bahwa Anda TIDAK membutuhkan kurung kurawal untuk try finally
, atau lambda, dan perhatikan penggunaan sintaksis tempat penampung. Perhatikan juga penamaan yang lebih baik.
implemented
prasyarat. Anda tidak dapat menggunakan kode yang tidak diterapkan. Maksud saya, Anda harus memberi tahu cara menemukannya karena tidak tersedia secara default dan tidak terkenal.
Berikut ini adalah kalimat singkat yang menggunakan pustaka kompiler Scala:
scala.tools.nsc.io.File("filename").writeAll("hello world")
Atau, jika Anda ingin menggunakan perpustakaan Java Anda bisa melakukan hack ini:
Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}
Satu liner untuk menyimpan / membaca ke / dari String
, menggunakan 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
}
Ini tidak cocok untuk file besar, tetapi akan melakukan pekerjaan.
Beberapa tautan:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
write
akan menyalin contents
ke array byte baru alih-alih streaming ke file, sehingga pada puncaknya menggunakan memori dua kali lebih banyak daripada contents
sendirian.
Sayangnya untuk jawaban teratas, Scala-IO sudah mati. Jika Anda tidak keberatan menggunakan ketergantungan pihak ketiga, pertimbangkan untuk menggunakan perpustakaan OS-Lib saya . Ini membuat bekerja dengan file, jalur dan sistem file sangat mudah:
// 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")
Ini memiliki satu-baris untuk menulis ke file , menambahkan file , menimpa file , dan banyak operasi lain yang berguna / umum
Perpustakaan mikro yang saya tulis: https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
atau
file << "Hello" << "\n" << "World"
Mulai Scala 2.13
, perpustakaan standar menyediakan utilitas manajemen sumber daya khusus: Using
.
Ini dapat digunakan dalam kasus ini dengan sumber daya seperti PrintWriter
atau BufferedWriter
yang meluas AutoCloseable
untuk menulis ke file dan, apa pun yang terjadi, tutup sumber daya setelahnya:
Misalnya, dengan 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)
}
Atau dengan 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"))
}
DIPERBARUI pada 2019 / Sep / 01:
finally
akan menelan asli Exception
dilemparkan oleh try
jika finally
kode melemparkanException
Setelah meninjau semua jawaban ini tentang cara mudah menulis file di Scala, dan beberapa di antaranya cukup bagus, saya punya tiga masalah:
scala.util.Try
close
metode ini dilakukan pada setiap sumber daya dependen dalam urutan terbalik - Catatan: menutup sumber daya dependen dalam urutan terbalik. TERUTAMA DALAM ACARA KEGAGALAN adalah persyaratan yang jarang dipahami oleh yang java.lang.AutoCloseable
spesifikasi yang cenderung menyebabkan sangat merusak dan sulit untuk menemukan bug dan kegagalan jangka waktuSebelum memulai, tujuan saya bukanlah keringkasan. Ini untuk memfasilitasi pemahaman yang lebih mudah bagi pemula Scala / FP, biasanya yang berasal dari Jawa. Pada akhirnya, saya akan mengumpulkan semua bit, dan kemudian meningkatkan keringkasannya.
Pertama, using
metode ini perlu diperbarui untuk digunakan Try
(sekali lagi, keringkasan bukanlah tujuan di sini). Itu akan diubah namanya menjadi 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
}
}
}
)
Awal tryUsingAutoCloseable
metode di atas mungkin membingungkan karena tampaknya memiliki dua daftar parameter, bukan daftar parameter tunggal biasa. Ini disebut kari. Dan saya tidak akan menjelaskan secara terperinci bagaimana kari bekerja atau di mana kadang berguna. Ternyata untuk ruang masalah khusus ini, ini adalah alat yang tepat untuk pekerjaan itu.
Selanjutnya, kita perlu membuat metode,, tryPrintToFile
yang akan membuat (atau menimpa yang sudah ada) File
dan menulis a List[String]
. Ini menggunakan FileWriter
yang dienkapsulasi oleh BufferedWriter
yang pada gilirannya dienkapsulasi oleh a PrintWriter
. Dan untuk meningkatkan kinerja, ukuran buffer standar jauh lebih besar dari standar untuk BufferedWriter
didefinisikan,defaultBufferSize
,, dan diberi nilai 65536.
Inilah kodenya (dan sekali lagi, keringkasan bukanlah tujuan di sini):
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))
)
}
}
}
}
tryPrintToFile
Metode di atas berguna karena dibutuhkan List[String]
input sebagai dan mengirimkannya ke a File
. Sekarang mari kita membuat tryWriteToFile
metode yang mengambil String
dan menulisnya ke File
.
Berikut kodenya (dan saya akan membiarkan Anda menebak prioritas keringkasan di sini):
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))
}
}
}
Akhirnya, berguna untuk dapat mengambil konten File
sebagai String
. Meskipun scala.io.Source
menyediakan metode yang mudah untuk mendapatkan konten a File
, close
metode tersebut harus digunakan pada Source
untuk melepaskan JVM dan sistem file yang menangani. Jika ini tidak dilakukan, maka sumber daya tidak dirilis sampai JVM GC (Pengumpul Sampah) sempat merilis Source
instance itu sendiri. Dan bahkan kemudian, hanya ada jaminan JVM yang lemah bahwa finalize
metode tersebut akan dipanggil oleh GC ke close
sumber daya. Ini berarti bahwa itu adalah tanggung jawab klien untuk secara eksplisit memanggil close
metode, sama seperti itu adalah tanggung jawab klien untuk menilai close
pada contoh darijava.lang.AutoCloseable
. Untuk ini, kita memerlukan definisi kedua dari metode using yang menangani scala.io.Source
.
Berikut kode untuk ini (masih belum ringkas):
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
}
}
}
)
Dan berikut ini adalah contoh penggunaannya dalam pembaca file streaming baris super sederhana (saat ini digunakan untuk membaca file yang dibatasi-tab dari output basis data):
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
)
)
Versi terbaru dari fungsi di atas telah disediakan sebagai jawaban untuk pertanyaan StackOverflow yang berbeda namun terkait .
Sekarang, menggabungkan semua itu dengan impor yang diekstraksi (membuatnya lebih mudah untuk ditempelkan ke lembar kerja Scala yang ada di plugin Eclipse ScalaIDE dan IntelliJ Scala untuk membuatnya lebih mudah untuk membuang output ke desktop agar lebih mudah diperiksa dengan editor teks), seperti inilah bentuk kode (dengan peningkatan keringkasan):
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
)
}
Sebagai pemula Scala / FP, saya telah menghabiskan banyak waktu (sebagian besar frustrasi kepala-menggaruk) mendapatkan pengetahuan dan solusi di atas. Saya harap ini membantu pemula Scala / FP lainnya mengatasi hump belajar ini lebih cepat.
try-catch-finally
. Cintailah gairah Anda.
Berikut adalah contoh penulisan beberapa baris ke file menggunakan 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
Untuk melampaui samthebest dan kontributor di depannya, saya telah meningkatkan penamaan dan keringkasan:
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
untuk penanganan kesalahandef 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")
}
Pembaruan 2019:
Ringkasan - Java NIO (atau NIO.2 untuk async) masih merupakan solusi pemrosesan file paling komprehensif yang didukung oleh Scala. Kode berikut membuat dan menulis beberapa teks ke file baru:
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
objek dengan nama file yang Anda pilihOutputStream
write
fungsi aliran output AndaMirip dengan jawaban ini , berikut adalah contoh dengan fs2
(versi 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)
}
}
Jika Anda memiliki Akka Streams di proyek Anda, itu menyediakan satu-liner:
def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}
Akka docs> Streaming File IO