Rex*_*err 209
这是标准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() }
}
Run Code Online (Sandbox Code Playgroud)
它的使用方式如下:
import java.io._
val data = Array("Five","strings","in","a","file!")
printToFile(new File("example.txt")) { p =>
data.foreach(p.println)
}
Run Code Online (Sandbox Code Playgroud)
Von*_*onC 70
编辑(2011年9月):自从Eduardo Costa询问Scala2.9以来,自从Rick-777评论scalax.IO承诺历史以来,自2009年中期以来几乎不存在......
Scala-IO改变了地方:从 Jesse Eichar(也在 SO上)看到它的 GitHub回购:
Scala IO总体项目包含一些针对IO的不同方面和扩展的子项目.
Scala IO有两个主要组件:
- 核心 - 核心主要处理从任意源和接收器读取和写入数据.基石特质
lihaoyi/os-lib,Using以及Input其提供的核心API.
其他重要的类别是Output,Seekable和Resource.- 文件 - 文件是一种
ReadChars(称为WriteChars)API,它基于Java 7 NIO文件系统和SBT PathFinder API的组合.
File并且Path是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)
Run Code Online (Sandbox Code Playgroud)
原始答案(2011年1月),scala-io的旧地方:
如果您不想等待Scala2.9,可以使用scala-incubator/scala-io库.
(如" Scala Source为什么不关闭底层的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)
}
Run Code Online (Sandbox Code Playgroud)
Jus*_*s12 49
类似于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() }
Run Code Online (Sandbox Code Playgroud)
然后我用它作为:
def writeToFile(fileName:String, data:String) =
using (new FileWriter(fileName)) {
fileWriter => fileWriter.write(data)
}
Run Code Online (Sandbox Code Playgroud)
和
def appendToFile(fileName:String, textData:String) =
using (new FileWriter(fileName, true)){
fileWriter => using (new PrintWriter(fileWriter)) {
printWriter => printWriter.println(textData)
}
}
Run Code Online (Sandbox Code Playgroud)
等等
sam*_*est 35
一个简单的答案:
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()
}
Run Code Online (Sandbox Code Playgroud)
sam*_*est 20
给出另一个答案,因为我对其他答案的编辑被拒绝了.
这是最简洁和简单的答案(类似于Garret Hall的)
File("filename").writeAll("hello world")
Run Code Online (Sandbox Code Playgroud)
这类似于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))
Run Code Online (Sandbox Code Playgroud)
请注意,您不需要花括号try finally,也不需要lambdas,并注意占位符语法的使用.还要注意更好的命名.
Gar*_*all 13
这是一个使用Scala编译器库的简洁单行程序:
__CODE__
或者,如果您想使用Java库,您可以执行以下操作:
__CODE__
Nic*_*kiy 13
一个用于保存/读取/ 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
}
Run Code Online (Sandbox Code Playgroud)
这不适合大文件,但可以完成这项工作.
一些链接:
java.nio.file.Files.write
java.lang.String.getBytes
scala.collection.JavaConverters
scala.collection.immutable.List.mkString
开始Scala 2.13,标准库提供了一个专用的资源管理实用程序:Using.
在这种情况下,它可以与资源一起使用,例如PrintWriter或BufferedWriter扩展AutoCloseable以写入文件,无论如何,之后关闭资源:
例如,使用java.ioapi:
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)
}
Run Code Online (Sandbox Code Playgroud)或者使用java.nioapi:
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"))
}
Run Code Online (Sandbox Code Playgroud)我写的一个微型库:https://github.com/pathikrit/better-files
file.appendLine("Hello", "World")
Run Code Online (Sandbox Code Playgroud)
要么
file << "Hello" << "\n" << "World"
Run Code Online (Sandbox Code Playgroud)
在回顾了关于如何在Scala中轻松编写文件的所有这些答案之后,其中一些非常好,我有三个问题:
finallyException以相反的顺序对每个依赖资源执行该方法 - 注意:以相反顺序关闭依赖资源特别是在失败的情况下很少被理解为在try这往往会导致非常有害的,难以规范,发现问题和运行时的故障在开始之前,我的目标不是简洁.这有助于更容易理解Scala/FP初学者,通常来自Java.在最后,我将把所有的位拉到一起,然后增加简洁性.
首先,finally需要更新该方法以使用Exception(同样,简洁性不是此处的目标).它将被重命名为scala.util.Try:
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
}
}
}
)
Run Code Online (Sandbox Code Playgroud)
上述close方法的开头可能会令人困惑,因为它似乎有两个参数列表而不是惯用的单个参数列表.这称为currying.我不会详细介绍如何使用currying或偶尔有用的地方.事实证明,对于这个特定的问题空间,它是适合这项工作的工具.
接下来,我们需要创建方法,java.lang.AutoCloseable它将创建一个(或覆盖现有的)using并编写一个Try.它使用一个tryUsingAutoCloseable封装的a tryUsingAutoCloseable,然后封装一个tryPrintToFile.和提升性能,默认缓冲区大小比默认为大得多的File定义,List[String]以及分配的值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))
)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的FileWriter方法很有用,因为它需要BufferedWriter输入并将其发送到PrintWriter.现在让我们创建一个BufferedWriter方法,它将a defaultBufferSize写入a tryPrintToFile.
这是代码(我会让你在这里猜测简洁性的优先级):
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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,它是能够的内容获取有用List[String]的File.虽然tryWriteToFile提供了一种方便的方法来轻松获取a的内容String,但File必须使用该方法File来释放底层的JVM和文件系统句柄.如果没有这样做,那么在JVM GC(垃圾收集器)绕过以释放String实例本身之前,资源不会被释放.即使这样,只有一个弱的JVM保证scala.io.SourceGC 将该方法调用到File资源.这意味着客户端有责任显式调用该close方法,就像客户端负责Source一个实例一样Source.为此,我们需要处理的using方法的第二个定义finalize.
这是代码(仍然不简洁):
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
}
}
}
)
Run Code Online (Sandbox Code Playgroud)
以下是超简单行流文件阅读器(目前用于从数据库输出中读取制表符分隔文件)的示例用法:
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
)
)
Run Code Online (Sandbox Code Playgroud)
已提供上述函数的更新版本作为对不同但相关的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
)
}
Run Code Online (Sandbox Code Playgroud)
作为一个Scala/FP的新手,我已经烧了好几个小时(主要是头疼的挫折),获得了上述知识和解决方案.我希望这有助于其他Scala/FP新手更快地克服这个特殊的学习驼峰.
不幸的是,对于最佳答案,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")
Run Code Online (Sandbox Code Playgroud)
它具有用于写入文件,附加到文件,覆盖文件以及许多其他有用/常用操作的单行代码
| 归档时间: |
|
| 查看次数: |
143439 次 |
| 最近记录: |