Towards simple, safe, sane I/O in Scala
import java.io.{File, BufferedWriter, FileOutputStream, FileWriter, OutputStreamWriter}
import scala.io.Codec
def append(file: File, text: String)(implicit codec: Codec): Unit = {
val fout = new FileOutputStream(file, true)
val writer = new BufferedWriter(new OutputStreamWriter(fout, codec.charSet))
try {
writer.append(text)
} finally {
fout.close()
writer.close()
}
}
import java.nio.file.{Files, Path}
def copy(source: Path, destination: Path): Unit = {
Files.copy(source, destination)
}
"Directories can be copied. However, files inside the directory are not copied, so the new directory is empty even when the original directory contains files."
https://docs.oracle.com/javase/tutorial/essential/io/copy.html
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{Files, Path, SimpleFileVisitor}
/**
* Scala port of https://docs.oracle.com/javase/tutorial/essential/io/examples/Copy.java
*/
def copy(source: Path, destination: Path): Unit = {
if(Files.isDirectory(source)) {
Files.walkFileTree(source, new SimpleFileVisitor[Path] {
def newPath(subPath: Path): Path = destination resolve (source relativize subPath)
override def preVisitDirectory(dir: Path, attrs: BasicFileAttributes) = {
Files.createDirectories(newPath(dir))
super.preVisitDirectory(dir, attrs)
}
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
Files.copy(file, newPath(file))
super.visitFile(file, attrs)
}
})
} else {
Files.copy(source, destination)
}
}
What if source and destination on different filesystems?
FileUtil.read(file) vs file.read()
scanner.nextInt() vs scanner.next[Int]
java.nio.Files.lines(myFile).count
import java.nio.file.{Files, Path}
def chown(file: Path, owner: String): Unit = {
Files.setOwner(file,
file.getFileSystem
.getUserPrincipalLookupService
.lookupPrincipalByName(owner)
)
}
rm! cwd/'target/'folder/'thing
scala.io.Codec, java.nio.file.LinkOption
"A drunken Martin Odersky sees a Reese's Peanut Butter Cup ad featuring somebody's peanut butter getting on somebody else's chocolate and has an idea. He creates Scala, a language that unifies constructs from both object oriented and functional languages. This pisses off both groups and each promptly declares jihad."
~James Iry (2009)
(A Brief, Incomplete, and Mostly Wrong History of Programming Languages)
Example: github.com/scala/slip/issues/19
trait File {
def append(text: String)(implicit codec: scala.io.Codec): File
def moveTo(destination: File, overwrite: Boolean = false): File
}
trait File {self =>
def append(text: String)(implicit codec: scala.io.Codec): self.type
def moveTo(destination: File, overwrite: Boolean = false): destination.type
}
(root/"tmp"/"diary.txt")
.createIfNotExists()
.appendLine()
.appendLines("My name is", "Inigo Montoya")
.moveTo(home/"Documents")
.renameTo("princess_diary.txt")
.changeExtensionTo(".md")
.lines
type Closeable = {
def close(): Unit
}
type ManagedResource[A <: Closeable] = Traversable[A]
implicit class CloseableOps[A <: Closeable](resource: A) {
def autoClosed: ManagedResource[A] = new Traversable[A] {
override def foreach[U](f: A => U) = try {
f(resource)
} finally {
resource.close()
}
}
}
for {
in <- file1.newInputStream.autoClosed
out <- file2.newOutputStream.autoClosed
} out.pipeTo(in)
(root/"tmp"/"diary.txt")
.createIfNotExists()
.appendLine()
.appendLines("My name is", "Inigo Montoya")
.moveTo(home/"Documents")
.renameTo("princess_diary.txt")
.changeExtensionTo(".md")
.lines
File.hasExtension
$25,000 referral bonus