Okumak için yararlı soyutlama var Source
. Bir metin dosyasına nasıl satır yazabilirim?
Okumak için yararlı soyutlama var Source
. Bir metin dosyasına nasıl satır yazabilirim?
Yanıtlar:
Düzen 2019 (8 yıl sonra), Scala-IO varsa çok aktif değil varlık Li Haoyi kendi kütüphanesini anlaşılacağı lihaoyi/os-lib
o, aşağıda sunulur .
Haziran 2019, Xavier Guihot bahsedildi onun cevabını kütüphanesini Using
, otomatik kaynak yönetimini gerçekleştirmek için bir yardımcı program.
Düzen (Eylül 2011): beri Eduardo Costa Scala2.9 sorar, ve o zamandan beri Rick-777 olduğunu comments scalax.IO geçmişini taahhüt mid-2009'dan beri hemen hemen yok denecek kadar ...
Scala-IO değiştirilen yere sahiptir: bkz GitHub Repo gelen, Jesse Eichar (ayrıca vb ):
Scala IO şemsiye projesi, IO'nun farklı yönleri ve uzantıları için birkaç alt projeden oluşmaktadır.
Scala IO'nun iki ana bileşeni vardır:
- Çekirdek - Çekirdek öncelikle keyfi kaynaklara ve lavabolara veri okuma ve yazma ile ilgilenir. Köşe taşı özellikleri vardır
Input
,Output
veSeekable
hangi çekirdek API sağlarlar.
Öneme sahip diğer sınıfları vardırResource
,ReadChars
veWriteChars
.- Dosya - Dosya, Java 7 NIO dosya sistemi ve SBT PathFinder API'lerinin bir kombinasyonunu temel alan
File
(denilenPath
) bir API'dir.
Path
veFileSystem
Scala IO Dosya API'sındaki ana giriş noktalarıdır.
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)
Orijinal cevap (Ocak 2011), eski skala yeri ile:
Scala2.9'u beklemek istemiyorsanız, scala-inkübatör / scala-io kütüphanesini kullanabilirsiniz.
(" Scala Kaynağı temeldeki InputStream'i neden kapatmıyor? " bölümünde belirtildiği gibi )
Örneklere bakın
{ // 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)
}
Bu, standart Scala'da eksik olan özelliklerden biri, kişisel kütüphaneme eklemem için çok yararlı buldum. (Muhtemelen kişisel bir kütüphaneniz de olmalıdır.) Kod şöyle:
def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) {
val p = new java.io.PrintWriter(f)
try { op(p) } finally { p.close() }
}
ve şu şekilde kullanılır:
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Source
(varsayılan olarak varsayılan kodlama). Elbette, eğer ortak bir ihtiyaç bulursanız, örneğin bir enc: Option[String] = None
parametre ekleyebilirsiniz f
.
Rex Kerr'ın cevabına benzer, ancak daha genel. İlk önce bir yardımcı işlev kullanıyorum:
/**
* 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() }
Sonra bunu şöyle kullanın:
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
ve
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
vb.
Basit bir cevap:
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
gelen kütüphaneleri ekleyebilir misiniz ?
Başka bir cevap vermek, çünkü reddettiğim yerlerde diğer cevapları düzenlemelerim.
Bu en özlü ve basit cevaptır (Garret Hall'unkine benzer)
File("filename").writeAll("hello world")
Bu Jus12'ye benzer, ancak ayrıntısızlık ve doğru kod stili olmadan
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))
Kıvırcık parantezlere try finally
veya lambdalara ihtiyacınız olmadığını ve yer tutucu sözdiziminin kullanımını not edin. Ayrıca daha iyi adlandırma not edin.
implemented
ön koşulu karşılamıyor . Uygulanmayan kodu kullanamazsınız. Yani, varsayılan olarak bulunmadığı ve iyi bilinmediği için onu nasıl bulacağınızı söylemelisiniz.
İşte Scala derleyici kitaplığını kullanan özlü bir tek katmanlı:
scala.tools.nsc.io.File("filename").writeAll("hello world")
Alternatif olarak, Java kitaplıklarını kullanmak istiyorsanız bu hack'i yapabilirsiniz:
Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}
String
Kullanarak kaydetmek / okumak için bir astar 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
}
Bu büyük dosyalar için uygun değildir, ancak işi yapar.
Bazı bağlantılar:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
write
kopyalayacağından contents
, contents
tek başına olduğundan iki kat daha fazla bellek kullanarak zirvede .
Ne yazık ki en iyi cevap için Scala-IO öldü. Üçüncü tarafa bağımlı olmanın bir sakıncası yoksa, OS-Lib kütüphanemi kullanmayı düşünün . Bu, dosyalar, yollar ve dosya sistemi ile çalışmayı çok kolaylaştırır:
// 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")
Bunun için bir gömlekler vardır dosyalara yazmak , dosyalara ekleyerek , dosyalar üzerine , ve diğer birçok faydalı / ortak operasyonlar
Yazdığım bir mikro kütüphane: https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
veya
file << "Hello" << "\n" << "World"
Başlangıçta Scala 2.13
, standart kütüphane özel bir kaynak yönetimi yardımcı programı sağlar:Using
.
Bu durumda, bir dosyaya yazmak için genişletilen PrintWriter
veya BufferedWriter
genişletilen kaynaklarla kullanılabilir AutoCloseable
ve ne olursa olsun, kaynağı daha sonra kapatın:
Örneğin, java.io
api ile:
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)
}
Veya java.nio
api ile:
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"))
}
2019 / Eylül / 01'de GÜNCELLEME:
finally
orijinal yutmak istiyorum Exception
tarafından atılan try
eğer finally
kod attıException
Scala'da bir dosyayı nasıl kolayca yazabileceğinizle ilgili tüm bu cevapları inceledikten ve bazıları oldukça güzel, üç sorunum vardı:
scala.util.Try
close
yöntem her bağımlı kaynak üzerinde ters sırayla gerçekleştirilir - Not: BAĞIMSIZLIK OLASINDA ÖZEL OLARAK bağımlı kaynakların ters sırada kapatılması nadiren anlaşılan bir gerekliliktir java.lang.AutoCloseable
çok tehlikeli ve zor yol açma eğilimindedir şartname böcek ve çalışma zamanı hataları bulmak içinBaşlamadan önce amacım kısa ve öz değil. Scala / FP yeni başlayanlar için, genellikle Java'dan gelenler için daha kolay anlaşılmasını sağlamaktır. En sonunda, tüm bitleri bir araya getireceğim ve daha sonra özlüğini artıracağım.
İlk olarak, using
yöntemin kullanmak için güncellenmesi gerekir Try
(yine, kısaca buradaki amaç değildir). Yeniden adlandırılacak 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
}
}
}
)
Yukarıdaki tryUsingAutoCloseable
yöntemin başlangıcı kafa karıştırıcı olabilir, çünkü alışılmış tekli parametre listesi yerine iki parametre listesi var gibi görünür. Buna körelme denir. Ve körüğün nasıl çalıştığını veya zaman zaman faydalı olduğu ayrıntılara girmeyeceğim . Bu özel sorun alanı için iş için doğru araç olduğu ortaya çıkıyor.
Daha sonra, tryPrintToFile
bir (veya var olanın üzerine File
yazacak ) ve a yazacak bir yöntem oluşturmamız gerekiyor List[String]
. Bir FileWriter
ile kapsüllenmiş olan bir kullanır, bu da a BufferedWriter
ile kapsüllenir PrintWriter
. Performansı artırmak için BufferedWriter
, varsayılan değerden çok daha büyük bir varsayılan arabellek boyutu tanımlanır,defaultBufferSize
ve 65536 değeri atanır.
İşte kod (ve yine, özlem burada amaç değildir):
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))
)
}
}
}
}
Yukarıdaki tryPrintToFile
yöntem, bir List[String]
as girişini alması ve a ' ya göndermesi açısından kullanışlıdır File
. Şimdi tryWriteToFile
a'yı alan String
ve a'ya yazan bir yöntem oluşturalım File
.
İşte kod (ve burada özlemin önceliğini tahmin etmenize izin vereceğim):
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))
}
}
}
Son olarak, a 'nın içeriğini File
a String
. Birlikte scala.io.Source
kolayca içeriğini elde etmek için uygun bir yöntem sağlar File
, close
yöntem kullanılmalıdır Source
temel JVM ve dosya sistemi kolları serbest bırakın. Bu yapılmazsa, JVM GC (Çöp Toplayıcı) Source
örneğin kendisini serbest bırakmaya başlayana kadar kaynak serbest bırakılmaz . Ve o zaman bile, finalize
yöntemin GC tarafından close
kaynağa çağrılacağı zayıf bir JVM garantisi vardır . Bu, açıkça çağrılmak müşterinin sorumluluğundadırclose
yöntemi , tıpkı bir müşterinin close
örneğinde uzun süre müşterinin sorumluluğunda olduğu gibijava.lang.AutoCloseable
. Bunun için, ele alan kullanım yönteminin ikinci bir tanımına ihtiyacımız var scala.io.Source
.
İşte bunun kodu (hala özlü değil):
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
}
}
}
)
Ve işte süper basit bir çizgi akışı dosya okuyucuda (şu anda sekme ile ayrılmış dosyaları veritabanı çıktısından okumak için kullanılıyor) bir örnek kullanım:
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
)
)
Bir Yukarıdaki fonksiyonun güncellenmiş sürümü bir cevap olarak sağlanmıştır farklı ancak ilişkili bir StackOverflow soru .
Şimdi, çıkarılan ithalat ile bir araya getirerek (hem bir Eclipse ScalaIDE hem de IntelliJ Scala eklentisinde bulunan Scala Çalışma Sayfasına yapıştırmayı çok daha kolay hale getirmek için, bir metin editörü ile daha kolay incelenmek üzere masaüstüne çıktı dökümü kolaylaştırmak için), kodun görünüşü budur (artan kısalık ile):
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
)
}
Bir Scala / FP acemi olarak, yukarıdaki bilgileri ve çözümleri kazanarak saatlerce (çoğunlukla kafa karıştırıcı hayal kırıklığı) yandım. Umarım bu, diğer Scala / FP yenilerinin bu özel öğrenme hızını daha hızlı aşmasına yardımcı olur.
try-catch-finally
. Hala tutkunu seviyorum.
İşte bir dosyaya scalaz-stream kullanarak bazı satırlar yazma örneği .
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
Samthebest'i ve ondan önceki katkıda bulunanları aşmak için, isimlendirme ve kısalığı geliştirdim:
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
hata işleme içindef 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")
}
2019 Güncellemesi:
Özet - Java NIO (veya async için NIO.2) hala Scala'da desteklenen en kapsamlı dosya işleme çözümüdür. Aşağıdaki kod, bazı metinleri yeni bir dosyaya oluşturur ve yazar:
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
Seçtiğiniz dosya adıyla bir nesne oluşturunOutputStream
write
işlevine aktarınBu yanıta benzer şekilde , fs2
(1.0.4 sürümü) ile bir örnek :
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)
}
}
Projenizde yine de Akka Akışları varsa, bir astar sağlar:
def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}
Akka belgeleri> Akış Dosyası ES