val f = File("/User/johndoe/Documents") // using constructor val f1: File = file"/User/johndoe/Documents"// using string interpolator val f2: File = "/User/johndoe/Documents".toFile // convert a string path to a file val f3: File = newJFile("/User/johndoe/Documents").toScala // convert a Java file to Scala val f4: File = root/"User"/"johndoe"/"Documents"// using root helper to start from root val f5: File = `~` / "Documents"// also equivalent to `home / "Documents"` val f6: File = "/User"/"johndoe"/"Documents"// using file separator DSL val f7: File = home/"Documents"/"presentations"/`..` // Use `..` to navigate up to parent
文件读写
可以一行搞定:
1 2 3 4
val file = root/"tmp"/"test.txt" file.overwrite("hello") file.appendLine().append("world") assert(file.contentAsString == "hello\nworld")
类似C++/Shell风格的读写,和上面的功能一样:
1 2 3
file < "hello"// same as file.overwrite("hello") file << "world"// same as file.appendLines("world") assert(file! == "hello\nworld")
val bytes : Iterator[Byte] = file.bytes val chars : Iterator[Char] = file.chars val lines : Iterator[String] = file.lines val source : scala.io.BufferedSource = file.newBufferedSource // needs to be closed, unlike the above APIs which auto closes when iterator ends
val file: File = tmp / "hello.txt" val javaFile : java.io.File = file.toJava val uri : java.net.uri = file.uri val reader : java.io.BufferedReader = file.newBufferedReader val outputstream : java.io.OutputStream = file.newOutputStream val writer : java.io.BufferedWriter = file.newBufferedWriter val inputstream : java.io.InputStream = file.newInputStream val path : java.nio.file.Path = file.path val fs : java.nio.file.FileSystem = file.fileSystem val channel : java.nio.channel.FileChannel = file.newFileChannel val ram : java.io.RandomAccessFile = file.newRandomAccess val fr : java.io.FileReader = file.newFileReader val fw : java.io.FileWriter = file.newFileWriter(append = true) val printer : java.io.PrintWriter = file.newPrintWriter
以及
1 2 3 4 5 6 7 8 9 10 11 12 13
file1.reader > file2.writer // pipes a reader to a writer System.in > file2.out // pipes an inputstream to an outputstream src.pipeTo(sink) // if you don't like symbols
val bytes : Iterator[Byte] = inputstream.bytes val bis : BufferedInputStream = inputstream.buffered val bos : BufferedOutputStream = outputstream.buffered val reader : InputStreamReader = inputstream.reader val writer : OutputStreamWriter = outputstream.writer val printer : PrintWriter = outputstream.printWriter val br : BufferedReader = reader.buffered val bw : BufferedWriter = writer.buffered val mm : MappedByteBuffer = fileChannel.toMappedByteBuffer
模式匹配
1 2 3 4 5 6 7 8 9 10 11
/** * @return true if file is a directory with no children or a file with no contents */ def isEmpty(file: File): Boolean = file match { case File.Type.SymbolicLink(to) => isEmpty(to) // this must be first case statement if you want to handle symlinks specially; else will follow link case File.Type.Directory(files) => files.isEmpty case File.Type.RegularFile(content) => content.isEmpty case _ => file.notExists // a file may not be one of the above e.g. UNIX pipes, sockets, devices etc } // or as extractors on LHS: val File.Type.Directory(researchDocs) = home/"Downloads"/"research"
通配符
1 2 3 4
val dir = "src"/"test" val matches: Iterator[File] = dir.glob("**/*.{java,scala}") // above code is equivalent to: dir.listRecursively.filter(f => f.extension == Some(".java") || f.extension == Some(".scala"))
甚至使用正则表达式:
1
val matches = dir.glob("^\\w*$")(syntax = File.PathMatcherSyntax.regex)
文件系统操作
文件系统操作也非常的便利:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
file.touch() file.delete() // unlike the Java API, also works on directories as expected (deletes children recursively) file.clear() // If directory, deletes all children; if file clears contents file.renameTo(newName: String) file.moveTo(destination) file.copyTo(destination) // unlike the default API, also works on directories (copies recursively) file.linkTo(destination) // ln file destination file.symbolicLinkTo(destination) // ln -s file destination file.{checksum, md5, sha1, sha256, sha512, digest} // also works for directories file.setOwner(user: String) // chown user file file.setGroup(group: String) // chgrp group file Seq(file1, file2) >: file3 // same as cat file1 file2 > file3 Seq(file1, file2) >>: file3 // same as cat file1 file2 >> file3 file.isReadLocked / file.isWriteLocked / file.isLocked File.newTemporaryDirectory() / File.newTemporaryFile() // create temp dir/file
import better.files_, Cmds._ // must import Cmds._ to bring in these utils pwd / cwd // current dir cp(file1, file2) mv(file1, file2) rm(file) /*or*/ del(file) ls(file) /*or*/ dir(file) ln(file1, file2) // hard link ln_s(file1, file2) // soft link cat(file1) cat(file1) >>: file touch(file) mkdir(file) mkdirs(file) // mkdir -p chown(owner, file) chgrp(owner, file) chmod_+(permission, files) // add permission chmod_-(permission, files) // remove permission md5(file) / sha1(file) / sha256(file) / sha512(file) unzip(zipFile)(targetDir) zip(file*)(zipFile)
文件属性
1 2 3 4 5 6 7 8 9 10 11 12 13
file.name // simpler than java.io.File#getName file.extension file.contentType file.lastModifiedTime // returns JSR-310 time file.owner / file.group file.isDirectory / file.isSymbolicLink / file.isRegularFile file.isHidden file.hide() / file.unhide() file.isOwnerExecutable / file.isGroupReadable // etc. see file.permissions file.size // for a directory, computes the directory size file.posixAttributes / file.dosAttributes // see file.attributes file.isEmpty // true if file has no content (or no children if directory) or does not exist file.isParentOf / file.isChildOf / file.isSiblingOf / file.siblings
// The following are all equivalent: assert(file.permissions contains PosixFilePermission.OWNER_EXECUTE) assert(file(PosixFilePermission.OWNER_EXECUTE)) assert(file.isOwnerExecutable)
文件比较
1 2 3 4
file1 == file2 // equivalent to `file1.isSamePathAs(file2)` file1 === file2 // equivalent to `file1.isSameContentAs(file2)` (works for regular-files and directories) file1 != file2 // equivalent to `!file1.isSamePathAs(file2)` file1 =!= file2 // equivalent to `!file1.isSameContentAs(file2)`
排序:
1 2 3 4 5 6
val files = myDir.list.toSeq files.sorted(File.Order.byName) files.max(File.Order.bySize) files.min(File.Order.byDepth) files.max(File.Order.byModificationTime) files.sorted(File.Order.byDirectoriesFirst)
压缩解压缩
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Unzipping: val zipFile: File = file"path/to/research.zip" val research: File = zipFile.unzipTo(destination = home/"Documents"/"research")
// Zipping: val zipFile: File = directory.zipTo(destination = home/"Desktop"/"toEmail.zip")
// Zipping/Unzipping to temporary files/directories: val someTempZipFile: File = directory.zip() val someTempDir: File = zipFile.unzip() assert(directory === someTempDir)