Scala IO操作有执行常用的文件处理任务,比如从文件中读取所有行或单词,或者读取包含数字的文件等。
要读取文件中所有行,可以调用scala.io.Source对象的getLines方法:
//导入Scala的IO包 import scala.io.Source //以指定的UTF-8字符集读取文件,第一个参数可以是字符串或者是java.io.File val source = Source.fromFile("ScalaTest.iml", "UTF-8") //或取文件中所有行 val lineIterator = source.getLines() //迭代打印所有行 lineIterator.foreach(println)
你可以对上例中的迭代器应用toArray或toBuffer方法,将这些行放到数组或数组缓冲中:
//将所有行放到数组中 val lines = source.getLines().toArray
有时候,你只想把整个文件读取成一个字符串,可以这样:
//将所有行读取成一个字符串 val contents = source.mkString
注意,在使用完Source对象后,记得调用Close关闭流
要从文件中读取单个字符,你可以直接把Source对象当做迭代器,因为Source类扩展自Iterator[Char]
val source = Source.fromFile("ScalaTest.iml", "UTF-8") for (c <- source) { //处理c (c为从文本文件中读取的单个字符) }
如果你想查看某个字符但又不处理它的话,可以调用source对象的buffered方法。这样你就可以用head方法查看下一个字符,但同时又不把它当做已处理的字符。
//导入Scala的IO包 import scala.io.Source //以指定的UTF-8字符集读取文件,第一个参数可以是字符串或者是java.io.File val source = Source.fromFile("ScalaTest.iml", "UTF-8") val iter = source.buffered while(iter.hasNext) { if(iter.head 是符合预期的) //处理 iter.next else // } source.close()
或者,如果你的文件不是很大,你也可以把它读取成一个字符串进行处理:
val contents = source.mkString
这里有一种快而脏的方式来读取源文件中所有以空格隔开的词法单元:
//导入Scala的IO包 import scala.io.Source //以指定的UTF-8字符集读取文件,第一个参数可以是字符串或者是java.io.File val source = Source.fromFile("ScalaTest.iml", "UTF-8") val tokens = source.mkString.split("\\s+") for (str <- tokens) println(str) source.close()
//导入Scala的IO包 import scala.io.Source //以指定的UTF-8字符集读取文件,第一个参数可以是字符串或者是java.io.File val source = Source.fromFile("kmeans_data.txt", "UTF-8") val tokens = source.mkString.split("\\s+") val numbers = tokens.map(_.toDouble) source.close()
//导入Scala的IO包 import scala.io.Source //以指定的UTF-8字符集从URL读取流 val source1 = Source.fromURL("www.baidu.com","UTF-8") //从字符串读取 val source2 = Source.fromString("Hello World!") //从标准输入读取 val source3 = Source.stdin val line = Console.readLine()
//导入java IO包 import java.io.{File, FileInputStream} //创建文件对象 val file = new File("kmeans_data.txt") //读取文件为字节流 val in = new FileInputStream(file) //创建字节数组 val bytes = new Array[Byte](file.length().toInt) //将字节流读入字节数组 val len = in.read(bytes) //把字节数组转成字符串输出 println(new String(bytes, 0, len)) //关闭流 in.close()
Scala没有内建的对写入文件的支持。要写入文本文件,可使用java.io.PrintWriter
例如:
//导入java IO包 import java.io.PrintWriter //创建打印流对象 val out = new PrintWriter("myfile.txt") for (i <- 1 to 100) out.println(i) //关闭打印流 out.close()
目前Scala并没有“正式的”用来访问某个目录中的所有文件,或者递归地遍历所有目录的类。不过可以使用一些替代方案。
遍历某目录下所有子目录的函数:
//导入java IO包 import java.io.File def subdirs(dir: File): Iterator[File] = { val children = dir.listFiles.filter(_.isDirectory) children.toIterator ++ children.toIterator.flatMap(subdirs _) } for(d <- subdirs(new File("F:\\Code\\scalacode"))){ println(d.getAbsolutePath) }
打印所有子目录的函数:
var dir = new File("F:\\Code\\scalacode") //导入java IO包 implicit def makeFileVisitor(f: (Path) => Unit) = new SimpleFileVisitor[Path] { override def visitFile(p: Path, attrs: BasicFileAttributes): FileVisitResult = { f(p) FileVisitResult.CONTINUE } } Files.walkFileTree((dir.toPath), (f: Path) => println(f))
在Java中,我们用序列化来将对象传输到其他虚拟机中,或临时存储。
Scala中声明一个可被序列化的类。
@SerialVersionUID(42L) class Person extends Serializable
Serializable特质定义在scala包,因此不需要显示引入。(如果你能够接受缺省的ID,也可略去@SerialVersionUID 的注解
你可以按照常规的方式对对象进行序列化和反序列化:
//创建Person对象fred val fred = new Person("Fred", 22) //导入java.io包 import java.io._ //指定写入的文件的路径文件名,创建对象写入流 val out = new ObjectOutputStream(new FileOutputStream("test.obj")) //写入序列化的对象 out.writeObject(fred) //关闭写入流 out.close() //创建对象读出流 val in = new ObjectInputStream(new FileInputStream("test.obj")) //读出序列化的对象 val saveFred = in.readObject().asInstanceOf[Person] //打印读出的Person信息 println(saveFred.name + " : " + saveFred.age)