ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Scala 中写入文件?

对于阅读,有一个有用的抽象 Source。如何将行写入文本文件?

如果您知道如何在 Java 中这样做,那么您可以在 Scala 中使用相同的方法。您的问题是专门针对 Scala 标准库的吗?
@wheaties 是的,最好的方法是在 scala 中做到这一点
这个库非常好:github.com/pathikrit/better-files
Lihaoyi 的 OS-Lib 库github.com/lihaoyi/os-lib

N
Ngoc Dao

这是标准 Scala 中缺少的功能之一,我发现它非常有用,因此我将其添加到我的个人库中。 (你可能也应该有一个个人图书馆。)代码如下:

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)
}

new java.io.PrintWriter() 使用平台默认编码,这可能意味着结果文件不是很便携。例如,如果您想生成一个稍后可以通过电子邮件发送的文件,您可能应该使用允许您指定编码的 PrintWriter 构造函数。
@JonaChristopherSahnwaldt - 当然,在特殊情况下,您可能想要指定编码。该平台的默认值平均而言是最合理的默认值。与 Source 相同(默认为默认编码)。如果您发现这是一种常见需求,您当然可以在 f 之后添加例如 enc: Option[String] = None 参数。
@RexKerr - 我不同意。几乎在所有情况下都应该指定编码。我遇到的大多数编码错误都是因为人们不理解或不考虑编码。他们使用默认值,甚至不知道它,因为太多的 API 让他们侥幸逃脱。如今,最明智的默认设置可能是 UTF-8。也许您只使用英语和其他可以用 ASCII 编写的语言。幸运的你。我住在德国,不得不修复比我想记住的更多的损坏的变音符号。
@JonaChristopherSahnwaldt - 这是有一个合理的默认编码的原因,而不是强迫每个人一直指定它。但是,如果您使用的是 Mac 并且您的由 Java 编写的文件是 gobbledygook,因为它们不是 Mac OS 罗马编码的,我不确定它的好处多于坏处。我认为他们没有就字符集达成一致是平台的错。作为个人开发者,输入字符串并不能真正解决问题。 (所有同意 UTF-8 的开发人员都会同意,但那可以作为默认设置。)
@JonaChristopherSahnwaldt +10 用于修复所有损坏的变音符号。不能用锤子,也许是打孔器?还是他们已经有洞需要填补,也许这家伙可以帮助youtube.com/watch?v=E-eBBzWEpwE但是说真的,ASCII的影响在世界上是如此具有破坏性,同意应该指定它,并且默认为UTF-8
V
VonC

编辑 2019 年(8 年后),Scala-IO 不是很活跃,如果有的话,Li Haoyi 建议他自己的图书馆 lihaoyi/os-lib,他presents below

2019 年 6 月,Xavier Guihothis answerUsing 中提到了一个用于执行自动资源管理的实用程序。

编辑(2011 年 9 月):因为 Eduardo Costa 询问 Scala2.9,并且因为 Rick-777 评论说 scalax.IO commit history 自 2009 年中期以来几乎不存在......

Scala-IO 已更改位置:查看其 GitHub repo,来自 Jesse Eichar(也称为 on SO):

Scala IO 伞形项目由几个子项目组成,用于 IO 的不同方面和扩展。 Scala IO 有两个主要组件: 核心 - 核心主要处理从任意源和接收器读取和写入数据。基石特征是提供核心 API 的 Input、Output 和 Seekable。其他重要的类别是 Resource、ReadChars 和 WriteChars。 File - File 是一个 File(称为 Path)API,它基于 Java 7 NIO 文件系统和 SBT PathFinder API 的组合。 Path 和 FileSystem 是 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)

原始答案(2011 年 1 月),带有 scala-io 的旧位置:

如果您不想等待 Scala2.9,可以使用 scala-incubator / scala-io 库。
(如“Why doesn't Scala Source close the underlying InputStream?”中所述)

请参阅the samples

{ // 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)
  }

Scala 2.9 版本怎么样? :)
scalax 项目似乎已经死了(自 2009 年 6 月以来没有提交)。这是正确的吗? scalax commit history
@Eduardo:我已经用 scala-io 库的新位置完成了我的回答(已针对 Scala2.9 进行了更新:github.com/jesseeichar/scala-io/issues/20
这真的是当前对 Scala 2.10 的建议吗?使用 Scala IO?核心 Scala 中还没有任何东西吗?
我从未使用过 scalax.io,但从这些示例行来看,它的 API 设计似乎很糟糕。在一个界面中混合字符和二进制数据的方法没有多大意义,并且很可能会导致难以发现的编码错误。 java.io(Reader/Writer vs. InputStream/OutputStream)的设计似乎要好得多。
J
Jus12

类似于 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)
    }
  }

等等


不要误会我的意思,我喜欢你的代码,而且它很有教育意义,但我越是看到这种简单问题的构造,它就越让我想起古老的“hello world”笑话:ariel.com.au/jokes/The_Evolution_of_a_Programmer.html :-) (+1我投票)。
如果您正在编写单行代码,那么一切都不重要。如果您正在编写重要的程序(大型程序需要持续维护和改进),这种想法会导致最快速和最有害的软件质量下降。
在一定程度的练习之前,并不是每个人都会有“scala 眼睛”——看到这个代码示例来自“Beginning”Scala 很有趣
asyncwait “开始” scala ......有史以来最具讽刺意味的标题,注意:我有这本书......现在我开始理解它......我想我比“初学者”更早一步哈哈:D ...........
问题不是这里的 Scala 技巧,而是冗长和糟糕的风格。我已将其编辑为更具可读性。在我重构之后,它只有 4 行(嗯,4 行带有 IDE 行长度,这里使用 6 来适应屏幕)。恕我直言,现在是非常好的答案。
D
Daniel Werner

一个简单的答案:

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()
  }

@samthebest 你能添加你import的库吗?
从 java 7 开始,请改用 java.nio.file: def writeToFile(file: String, stringToWrite: String): Unit = { val writer = Files.newBufferedWriter(Paths.get(file)) 最后尝试 writer.write(stringToWrite) writer.close() }
s
samthebest

给出另一个答案,因为我对其他答案的编辑被拒绝了。

这是最简洁的答案(类似于 Garret Hall 的)

File("filename").writeAll("hello world")

这类似于 Jus12,但没有冗长和正确的 code style

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 的花括号,也不需要 lambda,并注意占位符语法的用法。还要注意更好的命名。


抱歉,您的代码是可以想象的,它不满足 implemented 先决条件。您不能使用未实现的代码。我的意思是你必须告诉如何找到它,因为它在默认情况下不可用并且不为人所知。
L
Li Haoyi

不幸的是,对于最佳答案,Scala-IO 已经死了。如果您不介意使用第三方依赖项,请考虑使用我的 OS-Lib library。这使得处理文件、路径和文件系统变得非常容易:

// 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")

它具有用于 writing to filesappending to filesoverwriting files 和许多其他有用/常见操作的单行代码


X
Xavier Guihot

这是使用 Scala 编译器库的简明单行代码:

scala.tools.nsc.io.File("filename").writeAll("hello world")

或者,如果你想使用 Java 库,你可以这样做:

Some(new PrintWriter("filename")).foreach{p => p.write("hello world"); p.close}

进口什么?即文件来自哪里?
Scala 编译器库。
不再可行(不在 Scala 2.11 中)
你在说什么? scala.tools.nsc.io.File("/tmp/myFile.txt") 适用于 Scala 2.11.8。
它现在在 scala.reflect.io.File
N
Nick Zalutskiy

使用 java.nio 向/从 String 保存/读取的一个衬垫。

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


为什么这不适合大文件?
@ChetanBhasin 可能是因为 write 会将 contents 复制到一个新的字节数组而不是将其流式传输到文件中,因此在其峰值使用的内存是单独使用 contents 的两倍。
X
Xavier Guihot

Scala 2.13 开始,标准库提供了一个专用的资源管理实用程序:Using

在这种情况下,它可以与扩展 AutoCloseablePrintWriterBufferedWriter 等资源一起使用,以便写入文件,无论如何,之后关闭资源:

例如,使用 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")) }


p
pathikrit

我写的一个微库:https://github.com/pathikrit/better-files

file.appendLine("Hello", "World")

或者

file << "Hello" << "\n" << "World"

在这里也是如此 - 这个问题是谷歌搜索如何使用 scala 编写文件时最热门的问题之一 - 现在您的项目已经变得更大,您可能想稍微扩展您的答案?
c
chaotic3quilibrium

2019/Sep/01 更新:

从 Scala 2.13 开始,更喜欢使用 scala.util.Using

修复了如果 finally 代码抛出异常,finally 会吞下 try 抛出的原始异常的错误

在查看了所有这些关于如何在 Scala 中轻松编写文件的答案(其中一些非常好)之后,我遇到了三个问题:

在 Jus12 的回答中,对于 Scala/FP 初学者来说,使用 helper 方法使用柯里化并不明显需要用 scala.util.Try 封装较低级别的错误。需要向刚接触 Scala/FP 的 Java 开发人员展示如何正确嵌套依赖资源,因此关闭方法以相反的顺序对每个依赖资源执行 - 注意:以相反的顺序关闭依赖资源,特别是在失败的情况下是 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 方法的开头可能会令人困惑,因为它似乎有两个参数列表,而不是通常的单个参数列表。这称为柯里化。我不会详细介绍 currying 的工作原理或它偶尔有用的地方。事实证明,对于这个特定的问题空间,它是适合这项工作的工具。

接下来,我们需要创建方法 tryPrintToFile,它将创建(或覆盖现有的)File 并写入 List[String]。它使用由 BufferedWriter 封装的 FileWriter,而 BufferedWriter 又由 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。现在让我们创建一个 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))
      }
  }
}

最后,能够将 File 的内容作为 String 获取是很有用的。虽然 scala.io.Source 提供了一种方便的方法来轻松获取 File 的内容,但必须在 Source 上使用 close 方法来释放底层 JVM 和文件系统句柄。如果不这样做,则在 JVM GC(垃圾收集器)开始释放 Source 实例本身之前,不会释放资源。即使这样,也只有一个弱 JVM 保证 GC 将调用 finalize 方法来 close 资源。这意味着显式调用 close 方法是客户的责任,就像客户在 java.lang.AutoCloseable 的实例上提高 close 的责任一样。为此,我们需要处理 scala.io.Source 的 using 方法的第二个定义。

这是此的代码(仍然不简洁):

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
      )
  )

已提供 updated version of the above function 作为对 different but related StackOverflow question 的回答。

现在,将所有这些与提取的导入结合在一起(使其更容易粘贴到 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
    )
  }

作为一个 Scala/FP 新手,我已经花费了很多时间(主要是令人头疼的挫折)来获得上述知识和解决方案。我希望这可以帮助其他 Scala/FP 新手更快地克服这个特殊的学习障碍。


令人难以置信的更新。唯一的问题是现在您有大约 100 行代码可以用 try-catch-finally 替换。还是爱你的热情。
@Observer 我会断言这是一个不准确的陈述。我所描述的模式实际上是减少客户端必须编写的样板数量,以确保正确处理 AutoCloseables 的关闭,同时还启用使用 scala.util.Try 的 Scala 惯用 FP 模式。如果您尝试通过手动写出 try/catch/finally 块来实现与我相同的效果,我想您会发现最终得到的样板文件比您想象的要多得多。因此,将所有样板推入 100 行 Scala 函数中具有显着的可读性价值。
抱歉,如果这听起来令人反感。尽管如此,我的观点是不需要这么多的代码,因为同样可以通过更简单的非功能方法来实现。就个人而言,我会写 try-finally 并进行一些额外的检查。它只是更短。如果我想使用包装器,ApacheUtils 可以使用所有的脏活。此外,所有标准的 Reader/Writers 都会关闭底层流,因此不需要您的 multipwrap。 PS:我已将我的投票从负一更改为正一以支持您的努力。所以,请不要怀疑我有恶意。
没有冒犯。
我理解你的观点。感谢讨论,我得考虑一下。祝你今天过得愉快!
C
Chris Martin

下面是使用 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

E
Epicurist

为了超越 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))

这使用依赖于反射的“鸭子打字”。在许多情况下,依赖反射是行不通的。
M
Matthias Braun

无依赖,有错误处理

仅使用标准库中的方法

如有必要,为文件创建目录

使用 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")
}

J
Janac Meena

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()
}

导入 Java 库:IO 和 NIO 使用您选择的文件名创建 Path 对象 将要插入文件的文本转换为字节数组 将文件作为流:OutputStream 将字节数组传递到输出流的写入函数关闭溪流


V
Valy Dia

this answer 类似,以下是 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)

  }
}

V
Vickyster

此行有助于从 Array 或 String 写入文件。

 new PrintWriter(outputPath) { write(ArrayName.mkString("")); close }

a
akauppi

如果你的项目中有 Akka Streams,它提供了一个单行:

def writeToFile(p: Path, s: String)(implicit mat: Materializer): Unit = {
  Source.single(ByteString(s)).runWith(FileIO.toPath(p))
}

Akka 文档 > Streaming File IO