如何在Scala中写入文件?

时间:2023-01-12 22:15:19

For reading, there is the useful abstraction Source. How can I write lines to a text file?

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

14 个解决方案

#1


67  

Edit (September 2011): since Eduardo Costa asks about Scala2.9, and since Rick-777 comments that scalax.IO commit history is pretty much non-existent since mid-2009...

编辑(2011年9月):因为Eduardo Costa询问了Scala2.9,而且自从Rick-777提出了scalax。IO承诺历史从2009年中期开始就不存在了……

Scala-IO has changed place: see its GitHub repo, from Jesse Eichar (also on SO):

Scala-IO已经发生了变化:从Jesse Eichar(也就是这样)看它的GitHub repo:

The Scala IO umbrella project consists of a few sub projects for different aspects and extensions of IO.
There are two main components of Scala IO:

Scala IO伞项目由几个子项目组成,用于不同方面和IO的扩展。Scala IO有两个主要组件:

  • Core - Core primarily deals with Reading and writing data to and from arbitrary sources and sinks. The corner stone traits are Input, Output and Seekable which provide the core API.
    Other classes of importance are Resource, ReadChars and WriteChars.
  • Core - Core主要处理从任意来源和接收器读取和写入数据。角石的特点是输入、输出和可渗透,提供核心API。其他重要的类别是资源、ReadChars和WriteChars。
  • File - File is a File (called Path) API that is based on a combination of Java 7 NIO filesystem and SBT PathFinder APIs.
    Path and FileSystem are the main entry points into the Scala IO File API.
  • File - File是一个基于Java 7 NIO文件系统和SBT PathFinder API结合的文件(称为Path) API。路径和文件系统是Scala 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)

Original answer (January 2011), with the old place for scala-io:

原答案(2011年1月),老地方的scala-io:

If you don't want to wait for Scala2.9, you can use the scala-incubator / scala-io library.
(as mentioned in "Why doesn't Scala Source close the underlying InputStream?")

如果您不想等待Scala2.9,可以使用scala-孵化器/ scala-io库。(正如“为什么Scala源代码不能关闭底层的InputStream?”)

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

#2


208  

This is one of the features missing from standard Scala that I have found so useful that I add it to my personal library. (You probably should have a personal library, too.) The code goes like so:

这是标准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() }
}

and it's used like this:

它是这样使用的:

import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
  data.foreach(p.println)
}

#3


47  

Similar to the answer by Rex Kerr, but more generic. First I use a helper function:

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

Then I use this as:

然后我用这个:

def writeToFile(fileName:String, data:String) = 
  using (new FileWriter(fileName)) {
    fileWriter => fileWriter.write(data)
  }

and

def appendToFile(fileName:String, textData:String) =
  using (new FileWriter(fileName, true)){ 
    fileWriter => using (new PrintWriter(fileWriter)) {
      printWriter => printWriter.println(textData)
    }
  }

etc.

等。

#4


31  

A simple answer:

一个简单的答案:

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

#5


20  

Giving another answer, because my edits of other answers where rejected.

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

This is the most concise and simple answer (similar to Garret Hall's)

这是最简洁、最简单的回答(类似于加雷特霍尔的)

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

This is similar to Jus12, but without the verbosity and with correct code style

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

Note you do NOT need the curly braces for try finally, nor lambdas, and note usage of placeholder syntax. Also note better naming.

注意,您不需要花括号来尝试最后,也不需要lambdas,并注意使用占位符语法。还要注意更好的命名。

#6


13  

One liners for saving/reading to/from String, using java.nio.

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

This isn't suitable for large files, but will do the job.

这并不适合大型文件,但是会完成任务。

Some links:

一些链接:

java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString

java.nio.file.Files。以写。getBytes scala.collection。JavaConverters scala.collection.immutable.List.mkString

#7


12  

Here is a concise one-liner using the Scala compiler library:

下面是一个使用Scala编译器库的简洁的一行程序:

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

scala.tools.nsc.io.File(“文件名”)。writeAll(“hello world”)

Alternatively, if you want to use the Java libraries you can do this hack:

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

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

一些(新PrintWriter(“文件名”))。foreach { p = > p。写(“hello world”);p.close }

From scala write string to file in one statement

从scala写字符串到文件在一个语句中。

#8


5  

A micro library I wrote: https://github.com/pathikrit/better-files

我所写的微程序库:https://github.com/pathikrit/makefile。

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

or

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

#9


3  

After reviewing all of these answers on how to easily write a file in Scala, and some of them are quite nice, I had three issues:

在回顾了如何轻松地在Scala中编写文件的所有这些答案之后,我有三个问题:

  1. In the Jus12's answer, the use of currying for the using helper method is non-obvious for Scala/FP beginners
  2. 在Jus12的答案中,对于Scala/FP初学者来说,对使用辅助方法的使用是不明显的。
  3. Needs to encapsulate lower level errors with scala.util.Try
  4. 需要用scala.util.Try来封装低级错误。
  5. Needs to show Java developers new to Scala/FP how to properly nest dependent resources so the close method is performed on each dependent resource in reverse order - Note: closing dependent resources in reverse order ESPECIALLY IN THE EVENT OF A FAILURE is a rarely understood requirement of the java.lang.AutoCloseable specification which tends to lead to very pernicious and difficult to find bugs and run time failures
  6. 需要向Scala/FP的Java开发人员展示如何正确地嵌套依赖资源,从而在每个依赖的资源上以相反的顺序执行关闭的方法——注意:在失败的情况下,以相反的顺序关闭依赖的资源是Java .lang的一个很少被理解的需求。自动关闭规范往往会导致非常有害和难以发现错误和运行时故障。

Before starting, my goal isn't conciseness. It's to facilitate easier understanding for Scala/FP beginners, typically those coming from Java. At the very end, I will pull all the bits together, and then increase the conciseness.

在开始之前,我的目标不是简洁。这是为了便于理解Scala/FP初学者,特别是来自Java的初学者。在最后,我将把所有的部分拉到一起,然后增加简洁性。

First, the using method needs to be updated to use Try (again, conciseness is not the goal here). It will be renamed to tryUsingAutoCloseable:

首先,使用方法需要更新以使用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 =>
        try
          transfer(autoCloseable)
        finally
          autoCloseable.close()
    )

The beginning of the above tryUsingAutoCloseable method might be confusing because it appears to have two parameter lists instead of the customary single parameter list. This is called currying. And I won't go into detail how currying works or where it is occasionally useful. It turns out that for this particular problem space, it's the right tool for the job.

上述tryUsingAutoCloseable方法的开头可能会令人困惑,因为它似乎有两个参数列表,而不是常规的单参数列表。这就是所谓的局部套用。我也不会详细讲一下,currying是如何工作的,或者它在哪里偶尔有用。事实证明,对于这个特殊的问题空间,它是工作的合适工具。

Next, we need to create method, tryPrintToFile, which will create a (or overwrite an existing) File and write a List[String]. It uses a FileWriter which is encapsulated by a BufferedWriter which is in turn encapsulated by a PrintWriter. And to elevate performance, a default buffer size much larger than the default for BufferedWriter is defined, defaultBufferSize, and assigned the value 65536.

接下来,我们需要创建方法tryPrintToFile,它将创建一个(或覆盖现有的)文件并编写一个列表[String]。它使用一个由BufferedWriter封装的FileWriter,它由一个PrintWriter封装。为了提高性能,默认的缓冲区大小要比BufferedWriter的默认值大得多,它是defaultBufferSize,并赋值为65536。

Here's the code (and again, conciseness is not the goal here):

这里是代码(再一次,简洁不是这里的目标):

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

The above tryPrintToFile method is useful in that it takes a List[String] as input and sends it to a File. Let's now create a tryWriteToFile method which takes a String and writes it to a File.

上面的tryPrintToFile方法很有用,它将一个列表[字符串]作为输入,并将其发送到一个文件。现在,让我们创建一个tryWriteToFile方法,该方法获取一个字符串并将其写入文件。

Here's the code (and I'll let you guess conciseness's priority here):

下面是代码(我将在这里让您猜测简洁性的优先级):

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

Finally, it is useful to be able to fetch the contents of a File as a String. While scala.io.Source provides a convenient method for easily obtaining the contents of a File, the close method must be used on the Source to release the underlying JVM and file system handles. If this isn't done, then the resource isn't released until the JVM GC (Garbage Collector) gets around to releasing the Source instance itself. And even then, there is only a weak JVM guarantee the finalize method will be called by the GC to close the resource. This means that it is the client's responsibility to explicitly call the close method, just the same as it is the responsibility of a client to tall close on an instance of java.lang.AutoCloseable. For this, we need a second definition of the using method which handles scala.io.Source.

最后,可以将文件的内容作为字符串获取。而io。Source提供了一种方便的方法来轻松获取文件的内容,必须在源上使用close方法来释放底层JVM和文件系统句柄。如果这还没有完成,那么直到JVM GC(垃圾收集器)开始释放源实例本身之后,才会释放资源。即使是这样,也只有一个弱的JVM保证最终的方法将被GC调用以关闭资源。这意味着客户的责任是显式地调用close方法,就像客户端在java.lang.AutoCloseable实例上的高度关闭一样。为此,我们需要使用处理scala.i . source的使用方法的第二个定义。

Here's the code for this (still not being concise):

下面是这个(仍然不简洁)的代码:

def tryUsingSource[S <: scala.io.Source, R]
  (instantiateSource: () => S)
  (transfer: S => scala.util.Try[R])
: scala.util.Try[R] =
  Try(instantiateSource())
    .flatMap(
      source =>
        try
          transfer(source))
        finally
          source.close()
    )

And here is an example usage of it in a super simple line streaming file reader (currently using to read tab delimited files from database output):

这里有一个在超级简单的行流文件阅读器中使用它的例子(当前使用从数据库输出读取制表符分隔文件):

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

An updated version of the above function has been provided as an answer to a different but related * question.

上述函数的更新版本作为对不同但相关的*问题的答案提供。


Now, bringing that all together with the imports extracted (making it much easier to paste into Scala Worksheet present in both Eclipse ScalaIDE and IntelliJ Scala plugin to make it easy to dump output to the desktop to be more easily examined with a text editor), this is what the code looks like (with increased conciseness):

现在,把所有的进口提取(使它更容易粘贴到Scala工作表在Eclipse ScalaIDE和IntelliJ Scala插件使其容易转储输出到桌面更容易检查文本编辑器),这是代码是什么样子(增加了简洁性):

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)(transfer: A => scala.util.Try[R]): scala.util.Try[R] =
  Try(instantiateAutoCloseable())
    .flatMap(
      autoCloseable =>
        try transfer(autoCloseable)) finally autoCloseable.close()
    )

def tryUsingSource[S <: scala.io.Source, R]
  (instantiateSource: () => S)(transfer: S => scala.util.Try[R]): scala.util.Try[R] =
  Try(instantiateSource())
    .flatMap(
      source =>
        try transfer(source)) finally source.close()
    )

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

As a Scala/FP newbie, I've burned many hours (in mostly head scratching frustration) earning the above knowledge and solutions. I hope this helps other Scala/FP newbies get over this particular learning hump faster.

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

#10


2  

Here's an example of writing some lines to a file using scalaz-stream.

这里有一个使用scalazo -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

#11


1  

To surpass samthebest and the contributors before him, I have improved the naming and conciseness:

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

#12


1  

No dependencies, with error handling

  • Uses methods from the standard library exclusively
  • 只使用标准库中的方法。
  • Creates directories for the file, if necessary
  • 如果需要,为文件创建目录。
  • Uses Either for error handling
  • 用于错误处理。

Code

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

Usage

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

#13


0  

This line helps to write a file from an Array or String.

这一行有助于从数组或字符串中写入文件。

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

#14


0  

If you are anyways having Akka Streams in your project, it provides a one-liner:

如果您的项目中有Akka流,它提供了一个一行:

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

Akka docs > Streaming File IO

Akka docs >流文件IO。

#1


67  

Edit (September 2011): since Eduardo Costa asks about Scala2.9, and since Rick-777 comments that scalax.IO commit history is pretty much non-existent since mid-2009...

编辑(2011年9月):因为Eduardo Costa询问了Scala2.9,而且自从Rick-777提出了scalax。IO承诺历史从2009年中期开始就不存在了……

Scala-IO has changed place: see its GitHub repo, from Jesse Eichar (also on SO):

Scala-IO已经发生了变化:从Jesse Eichar(也就是这样)看它的GitHub repo:

The Scala IO umbrella project consists of a few sub projects for different aspects and extensions of IO.
There are two main components of Scala IO:

Scala IO伞项目由几个子项目组成,用于不同方面和IO的扩展。Scala IO有两个主要组件:

  • Core - Core primarily deals with Reading and writing data to and from arbitrary sources and sinks. The corner stone traits are Input, Output and Seekable which provide the core API.
    Other classes of importance are Resource, ReadChars and WriteChars.
  • Core - Core主要处理从任意来源和接收器读取和写入数据。角石的特点是输入、输出和可渗透,提供核心API。其他重要的类别是资源、ReadChars和WriteChars。
  • File - File is a File (called Path) API that is based on a combination of Java 7 NIO filesystem and SBT PathFinder APIs.
    Path and FileSystem are the main entry points into the Scala IO File API.
  • File - File是一个基于Java 7 NIO文件系统和SBT PathFinder API结合的文件(称为Path) API。路径和文件系统是Scala 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)

Original answer (January 2011), with the old place for scala-io:

原答案(2011年1月),老地方的scala-io:

If you don't want to wait for Scala2.9, you can use the scala-incubator / scala-io library.
(as mentioned in "Why doesn't Scala Source close the underlying InputStream?")

如果您不想等待Scala2.9,可以使用scala-孵化器/ scala-io库。(正如“为什么Scala源代码不能关闭底层的InputStream?”)

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

#2


208  

This is one of the features missing from standard Scala that I have found so useful that I add it to my personal library. (You probably should have a personal library, too.) The code goes like so:

这是标准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() }
}

and it's used like this:

它是这样使用的:

import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
  data.foreach(p.println)
}

#3


47  

Similar to the answer by Rex Kerr, but more generic. First I use a helper function:

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

Then I use this as:

然后我用这个:

def writeToFile(fileName:String, data:String) = 
  using (new FileWriter(fileName)) {
    fileWriter => fileWriter.write(data)
  }

and

def appendToFile(fileName:String, textData:String) =
  using (new FileWriter(fileName, true)){ 
    fileWriter => using (new PrintWriter(fileWriter)) {
      printWriter => printWriter.println(textData)
    }
  }

etc.

等。

#4


31  

A simple answer:

一个简单的答案:

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

#5


20  

Giving another answer, because my edits of other answers where rejected.

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

This is the most concise and simple answer (similar to Garret Hall's)

这是最简洁、最简单的回答(类似于加雷特霍尔的)

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

This is similar to Jus12, but without the verbosity and with correct code style

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

Note you do NOT need the curly braces for try finally, nor lambdas, and note usage of placeholder syntax. Also note better naming.

注意,您不需要花括号来尝试最后,也不需要lambdas,并注意使用占位符语法。还要注意更好的命名。

#6


13  

One liners for saving/reading to/from String, using java.nio.

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

This isn't suitable for large files, but will do the job.

这并不适合大型文件,但是会完成任务。

Some links:

一些链接:

java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString

java.nio.file.Files。以写。getBytes scala.collection。JavaConverters scala.collection.immutable.List.mkString

#7


12  

Here is a concise one-liner using the Scala compiler library:

下面是一个使用Scala编译器库的简洁的一行程序:

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

scala.tools.nsc.io.File(“文件名”)。writeAll(“hello world”)

Alternatively, if you want to use the Java libraries you can do this hack:

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

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

一些(新PrintWriter(“文件名”))。foreach { p = > p。写(“hello world”);p.close }

From scala write string to file in one statement

从scala写字符串到文件在一个语句中。

#8


5  

A micro library I wrote: https://github.com/pathikrit/better-files

我所写的微程序库:https://github.com/pathikrit/makefile。

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

or

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

#9


3  

After reviewing all of these answers on how to easily write a file in Scala, and some of them are quite nice, I had three issues:

在回顾了如何轻松地在Scala中编写文件的所有这些答案之后,我有三个问题:

  1. In the Jus12's answer, the use of currying for the using helper method is non-obvious for Scala/FP beginners
  2. 在Jus12的答案中,对于Scala/FP初学者来说,对使用辅助方法的使用是不明显的。
  3. Needs to encapsulate lower level errors with scala.util.Try
  4. 需要用scala.util.Try来封装低级错误。
  5. Needs to show Java developers new to Scala/FP how to properly nest dependent resources so the close method is performed on each dependent resource in reverse order - Note: closing dependent resources in reverse order ESPECIALLY IN THE EVENT OF A FAILURE is a rarely understood requirement of the java.lang.AutoCloseable specification which tends to lead to very pernicious and difficult to find bugs and run time failures
  6. 需要向Scala/FP的Java开发人员展示如何正确地嵌套依赖资源,从而在每个依赖的资源上以相反的顺序执行关闭的方法——注意:在失败的情况下,以相反的顺序关闭依赖的资源是Java .lang的一个很少被理解的需求。自动关闭规范往往会导致非常有害和难以发现错误和运行时故障。

Before starting, my goal isn't conciseness. It's to facilitate easier understanding for Scala/FP beginners, typically those coming from Java. At the very end, I will pull all the bits together, and then increase the conciseness.

在开始之前,我的目标不是简洁。这是为了便于理解Scala/FP初学者,特别是来自Java的初学者。在最后,我将把所有的部分拉到一起,然后增加简洁性。

First, the using method needs to be updated to use Try (again, conciseness is not the goal here). It will be renamed to tryUsingAutoCloseable:

首先,使用方法需要更新以使用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 =>
        try
          transfer(autoCloseable)
        finally
          autoCloseable.close()
    )

The beginning of the above tryUsingAutoCloseable method might be confusing because it appears to have two parameter lists instead of the customary single parameter list. This is called currying. And I won't go into detail how currying works or where it is occasionally useful. It turns out that for this particular problem space, it's the right tool for the job.

上述tryUsingAutoCloseable方法的开头可能会令人困惑,因为它似乎有两个参数列表,而不是常规的单参数列表。这就是所谓的局部套用。我也不会详细讲一下,currying是如何工作的,或者它在哪里偶尔有用。事实证明,对于这个特殊的问题空间,它是工作的合适工具。

Next, we need to create method, tryPrintToFile, which will create a (or overwrite an existing) File and write a List[String]. It uses a FileWriter which is encapsulated by a BufferedWriter which is in turn encapsulated by a PrintWriter. And to elevate performance, a default buffer size much larger than the default for BufferedWriter is defined, defaultBufferSize, and assigned the value 65536.

接下来,我们需要创建方法tryPrintToFile,它将创建一个(或覆盖现有的)文件并编写一个列表[String]。它使用一个由BufferedWriter封装的FileWriter,它由一个PrintWriter封装。为了提高性能,默认的缓冲区大小要比BufferedWriter的默认值大得多,它是defaultBufferSize,并赋值为65536。

Here's the code (and again, conciseness is not the goal here):

这里是代码(再一次,简洁不是这里的目标):

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

The above tryPrintToFile method is useful in that it takes a List[String] as input and sends it to a File. Let's now create a tryWriteToFile method which takes a String and writes it to a File.

上面的tryPrintToFile方法很有用,它将一个列表[字符串]作为输入,并将其发送到一个文件。现在,让我们创建一个tryWriteToFile方法,该方法获取一个字符串并将其写入文件。

Here's the code (and I'll let you guess conciseness's priority here):

下面是代码(我将在这里让您猜测简洁性的优先级):

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

Finally, it is useful to be able to fetch the contents of a File as a String. While scala.io.Source provides a convenient method for easily obtaining the contents of a File, the close method must be used on the Source to release the underlying JVM and file system handles. If this isn't done, then the resource isn't released until the JVM GC (Garbage Collector) gets around to releasing the Source instance itself. And even then, there is only a weak JVM guarantee the finalize method will be called by the GC to close the resource. This means that it is the client's responsibility to explicitly call the close method, just the same as it is the responsibility of a client to tall close on an instance of java.lang.AutoCloseable. For this, we need a second definition of the using method which handles scala.io.Source.

最后,可以将文件的内容作为字符串获取。而io。Source提供了一种方便的方法来轻松获取文件的内容,必须在源上使用close方法来释放底层JVM和文件系统句柄。如果这还没有完成,那么直到JVM GC(垃圾收集器)开始释放源实例本身之后,才会释放资源。即使是这样,也只有一个弱的JVM保证最终的方法将被GC调用以关闭资源。这意味着客户的责任是显式地调用close方法,就像客户端在java.lang.AutoCloseable实例上的高度关闭一样。为此,我们需要使用处理scala.i . source的使用方法的第二个定义。

Here's the code for this (still not being concise):

下面是这个(仍然不简洁)的代码:

def tryUsingSource[S <: scala.io.Source, R]
  (instantiateSource: () => S)
  (transfer: S => scala.util.Try[R])
: scala.util.Try[R] =
  Try(instantiateSource())
    .flatMap(
      source =>
        try
          transfer(source))
        finally
          source.close()
    )

And here is an example usage of it in a super simple line streaming file reader (currently using to read tab delimited files from database output):

这里有一个在超级简单的行流文件阅读器中使用它的例子(当前使用从数据库输出读取制表符分隔文件):

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

An updated version of the above function has been provided as an answer to a different but related * question.

上述函数的更新版本作为对不同但相关的*问题的答案提供。


Now, bringing that all together with the imports extracted (making it much easier to paste into Scala Worksheet present in both Eclipse ScalaIDE and IntelliJ Scala plugin to make it easy to dump output to the desktop to be more easily examined with a text editor), this is what the code looks like (with increased conciseness):

现在,把所有的进口提取(使它更容易粘贴到Scala工作表在Eclipse ScalaIDE和IntelliJ Scala插件使其容易转储输出到桌面更容易检查文本编辑器),这是代码是什么样子(增加了简洁性):

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)(transfer: A => scala.util.Try[R]): scala.util.Try[R] =
  Try(instantiateAutoCloseable())
    .flatMap(
      autoCloseable =>
        try transfer(autoCloseable)) finally autoCloseable.close()
    )

def tryUsingSource[S <: scala.io.Source, R]
  (instantiateSource: () => S)(transfer: S => scala.util.Try[R]): scala.util.Try[R] =
  Try(instantiateSource())
    .flatMap(
      source =>
        try transfer(source)) finally source.close()
    )

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

As a Scala/FP newbie, I've burned many hours (in mostly head scratching frustration) earning the above knowledge and solutions. I hope this helps other Scala/FP newbies get over this particular learning hump faster.

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

#10


2  

Here's an example of writing some lines to a file using scalaz-stream.

这里有一个使用scalazo -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

#11


1  

To surpass samthebest and the contributors before him, I have improved the naming and conciseness:

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

#12


1  

No dependencies, with error handling

  • Uses methods from the standard library exclusively
  • 只使用标准库中的方法。
  • Creates directories for the file, if necessary
  • 如果需要,为文件创建目录。
  • Uses Either for error handling
  • 用于错误处理。

Code

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

Usage

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

#13


0  

This line helps to write a file from an Array or String.

这一行有助于从数组或字符串中写入文件。

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

#14


0  

If you are anyways having Akka Streams in your project, it provides a one-liner:

如果您的项目中有Akka流,它提供了一个一行:

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

Akka docs > Streaming File IO

Akka docs >流文件IO。