읽기에는 유용한 추상화가 Source
있습니다. 텍스트 파일에 줄을 쓰려면 어떻게해야합니까?
읽기에는 유용한 추상화가 Source
있습니다. 텍스트 파일에 줄을 쓰려면 어떻게해야합니까?
답변:
편집 2019 (8 년 이상), 스칼라-IO가 있는 경우, 매우 활성화되지되는 리튬 Haoyi가 자신의 라이브러리를 제안 lihaoyi/os-lib
그가 것을, 아래에 제시한다 .
2019 년 6 월 Xavier Guihot 은 자신의 답변 에 Using
자동 리소스 관리를 수행하는 유틸리티 인 라이브러리를 언급했습니다 .
편집 (2011 년 9 월) : Eduardo Costa 가 Scala2.9에 대해 질문 한 후 Rick-777 이 scalax.IO 커밋 기록 이 2009 년 중반 이후 거의 존재하지 않는다고 언급 한 이후로 ...
스칼라-IO가 변경된 곳이 : 그 볼 GitHub의의의 repo 에서 제시 Eichar (또한 SO에를 )
Scala IO 우산 프로젝트는 IO의 다양한 측면과 확장을위한 몇 가지 하위 프로젝트로 구성됩니다.
스칼라 IO에는 두 가지 주요 구성 요소가 있습니다.
- 코어 -코어는 주로 임의의 소스 및 싱크에서 데이터를 읽고 쓰는 것을 처리합니다. 코너 스톤의 특징은
Input
,Output
하고Seekable
있는 핵심 API를 제공합니다.
중요성의 다른 클래스는Resource
,ReadChars
하고WriteChars
.- File -File은 Java 7 NIO 파일 시스템과 SBT PathFinder API의 조합을 기반으로 하는
File
(라 불리는Path
) API입니다.
Path
및FileSystem
스칼라 IO 파일 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)
scala-io의 이전 장소가 포함 된 원본 답변 (2011 년 1 월) :
Scala2.9를 기다리지 않으려면 scala-incubator / scala-io 라이브러리를 사용할 수 있습니다 .
( " 스칼라 소스는 왜 기본 InputStream을 닫지 않습니까? "
샘플 보기
{ // 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)
}
이것은 표준 스칼라에서 누락 된 기능 중 하나이므로 개인 라이브러리에 추가 할 때 유용합니다. (개인 라이브러리도 있어야합니다.) 코드는 다음과 같습니다.
def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) {
val p = new java.io.PrintWriter(f)
try { op(p) } finally { p.close() }
}
다음과 같이 사용됩니다.
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Source
(기본적으로 기본 인코딩). 물론 일반적인 요구가 발견되면 enc: Option[String] = None
매개 변수를 추가 할 수 있습니다 f
.
Rex Kerr의 답변과 비슷하지만 더 일반적입니다. 먼저 도우미 기능을 사용합니다.
/**
* 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() }
그런 다음 이것을 다음과 같이 사용합니다.
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
과
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
기타
간단한 답변 :
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
있습니까?
다른 답변에 대한 수정 사항이 거부 된 경우 다른 답변을 제공합니다.
이것은 가장 간결하고 간단한 답변입니다 (가렛 홀과 유사)
File("filename").writeAll("hello world")
이것은 Jus12와 비슷하지만 자세한 정보가없고 올바른 코드 스타일이 있습니다.
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))
에 대한 중괄호 try finally
나 람다 가 필요하지 않으며 자리 표시 자 구문의 사용법에 유의하십시오. 또한 더 나은 명명을 참고하십시오.
implemented
필수 구성 요소를 충족하지 못합니다 . 구현되지 않은 코드는 사용할 수 없습니다. 기본적으로 사용할 수없고 잘 알려지지 않았기 때문에 찾는 방법을 알려 주어야합니다.
스칼라 컴파일러 라이브러리를 사용하는 간결한 원 라이너는 다음과 같습니다.
scala.tools.nsc.io.File("filename").writeAll("hello world")
또는 Java 라이브러리를 사용하려는 경우 다음 해킹을 수행 할 수 있습니다.
Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}
을 (를 String
) 사용하여 저장 / 읽기위한 하나의 라이너 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
}
큰 파일에는 적합하지 않지만 작업을 수행합니다.
일부 링크 :
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
write
복사 contents
하기 때문에 contents
혼자서 보다 두 배나 많은 메모리를 사용하기 때문 입니다.
불행히도 최고의 답변으로 Scala-IO는 죽었습니다. 타사 종속성을 사용하지 않으려면 OS-Lib 라이브러리 사용을 고려하십시오 . 파일, 경로 및 파일 시스템 작업이 매우 쉽습니다.
// 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")
파일 쓰기 , 파일 추가 , 파일 덮어 쓰기 및 기타 여러 유용한 / 공통 작업을 위한 하나의 라이너가 있습니다.
내가 쓴 마이크로 라이브러리 : https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
또는
file << "Hello" << "\n" << "World"
시작 Scala 2.13
, 표준 라이브러리는 전용 자원 관리 유틸리티를 제공합니다 Using
.
이 경우 파일에 쓰기 위해 확장 PrintWriter
되거나 BufferedWriter
확장되는 자원과 함께 사용할 수 있으며 AutoCloseable
이후에 자원을 닫을 수 있습니다.
예를 들어 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)
}
또는 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"))
}
2019/9/01의 업데이트 :
finally
원래 삼키려 Exception
에 의해 발생 try
하는 경우 finally
코드가 던져Exception
스칼라에서 파일을 쉽게 작성하는 방법에 대한이 모든 답변을 검토 한 결과 일부는 꽤 좋았으므로 세 가지 문제가있었습니다.
scala.util.Try
close
방법은 역순으로 각 의존 자원에서 수행됩니다 - 참고 : 역순으로 따라 자원을 닫는 특히에 오류가 발생하는 의 거의 이해하지 요구 사항입니다 java.lang.AutoCloseable
매우 치명적이고 버그를 찾기 어렵고 런타임 실패를 일으키는 경향이 있는 사양시작하기 전에 내 목표는 간결하지 않습니다. Scala / FP 초보자, 일반적으로 Java에서 온 사람들이 쉽게 이해할 수 있도록합니다. 마지막에 모든 비트를 모아 간결성을 높이겠습니다.
먼저,이 using
방법을 사용하려면 업데이트해야합니다 Try
(다시 말해 간결함은 여기서 목표가 아닙니다). 이름이 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
}
}
}
)
위의 tryUsingAutoCloseable
방법 의 시작은 일반적인 단일 매개 변수 목록 대신 두 개의 매개 변수 목록이있는 것처럼 보이기 때문에 혼란 스러울 수 있습니다. 이것을 카레라고합니다. 그리고 나는 카레가 어떻게 작동하는지 또는 때로는 유용한 곳을 자세히 설명하지 않을 것 입니다. 이 특정 문제 공간의 경우 작업에 적합한 도구라는 것이 밝혀졌습니다.
다음으로, 우리는 방법을 만들어야 tryPrintToFile
하는을 작성 (또는 기존 덮어 쓰기) 할 File
및 쓰기 List[String]
. 에 FileWriter
의해 캡슐화되는 a BufferedWriter
를 사용하고 ,에 의해 캡슐화되는 a를 사용 PrintWriter
합니다. 성능을 높이기 위해 기본값보다 훨씬 큰 기본 버퍼 크기 BufferedWriter
가 정의 defaultBufferSize
되어 값 65536이 지정됩니다.
코드는 다음과 같습니다 (그리고 간결함은 여기서 목표가 아닙니다).
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
방법은 List[String]
입력을 받아로 전송 한다는 점에서 유용 합니다 File
. 이제 a tryWriteToFile
를 가져 와서에 String
쓰는 메소드를 만들어 봅시다 File
.
코드는 다음과 같습니다 (여기서 간결함의 우선 순위를 추측하도록하겠습니다).
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))
}
}
}
마지막으로 a의 내용을 페치 할 수있는 것이 유용 File
합니다 String
. 하지만 scala.io.Source
쉽게의 내용을 얻기위한 편리한 방법을 제공 File
의 close
방법은 사용해야합니다 Source
기본 JVM 및 파일 시스템 핸들을 해제 할 수 있습니다. 이 작업을 수행하지 않으면 JVM GC (Garbage Collector)가 Source
인스턴스 자체 를 해제 할 때까지 리소스가 해제되지 않습니다 . 그럼에도 불구 finalize
하고 GC가 close
리소스 에 메소드를 호출 한다는 보장은 약한 JVM 입니다. 즉 , 인스턴스를 작성하는 close
것은 클라이언트의 책임과 마찬가지로 메소드 를 명시 적으로 호출하는 것은 클라이언트의 책임 close
입니다.java.lang.AutoCloseable
. 이를 위해를 처리하는 using 메소드의 두 번째 정의가 필요합니다 scala.io.Source
.
이것에 대한 코드는 다음과 같습니다 (아직 간결하지는 않음).
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 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
)
)
위 함수 의 업데이트 된 버전은 다르지만 관련된 StackOverflow 질문에 대한 답변으로 제공되었습니다 .
이제 가져 오기 한 가져 오기와 함께 가져옵니다 (Eclipse ScalaIDE 및 IntelliJ Scala 플러그인 모두에있는 Scala Worksheet에 붙여 넣기가 훨씬 쉬워 져서 텍스트 편집기로보다 쉽게 검사 할 수 있도록 데스크탑에 출력을 덤프하는 것이 더 쉬워졌습니다). 이 코드는 다음과 같습니다 (간결성이 증가 함).
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
)
}
스칼라 / FP 초보자로서 위의 지식과 솔루션을 얻기 위해 많은 시간을 쏟았습니다 (주로 머리를 긁적 좌절감으로). 이것이 다른 스칼라 / FP 초보자들이이 특정 학습 혹을 더 빨리 극복하는 데 도움이되기를 바랍니다.
try-catch-finally
. 여전히 당신의 열정을 사랑하십시오.
다음은 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
samthebest와 그 앞에 기여한 사람들을 능가하기 위해 나는 이름과 간결성을 개선했습니다.
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
오류 처리에 대한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 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 년 업데이트 :
요약-Java NIO (또는 비동기 용 NIO.2)는 여전히 Scala에서 지원되는 가장 포괄적 인 파일 처리 솔루션입니다. 다음 코드는 텍스트를 작성하여 새 파일에 씁니다.
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
선택한 파일 이름 객체OutputStream
write
함수에 전달이 답변 과 마찬가지로 fs2
(버전 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)
}
}
어쨌든 프로젝트에 Akka Streams가있는 경우 하나의 라이너를 제공합니다.
def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}
Akka Docs> 스트리밍 파일 IO