Scala--IO操作

  I/O我想大家并不陌生了,即输入/输出(Input/Output)。本篇博客,我想看标题就清楚了,就是带着大家一起来看看scala的IO操作。

读取文件

基本读取文件

读取文件我们使用scala.io.Source,如下图所示,注意的是,在大部分读写操作的过程中就是引入了java.io包下面的方法。

  • 读取文件,常用Source.fromFile("文件路径","字符编码")如下图所示:

当然我们也可以使用fromIterablefromCharfromCharsfromBytesfromURLfromInputStream等读取信息,博客中会讲解,下面先来看看Source.fromFile。

  • 主要讲解的是Source.fromFile读取文件,事例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
ackage com.xiaoxiaomo.demo.ch09

import java.io.{PrintWriter, File}

import scala.io.{BufferedSource, Source}

/**
* 读取文件
* Created by xiaoxiaomo on 2016/4/5.
*/

object ReadLines {

//TEST
def main(args: Array[String]) {
//读取文件,事例一
val source: BufferedSource = Source.fromFile(new File("D:\\test.txt"),"UTF-8")
//读取文件,事例二(new File可以省略,字符编码如果省略默认使用缺省值)
val source2: BufferedSource = Source.fromFile("D:\\test.txt","UTF-8")

//遍历的方式一,直接String输出
//print(source.mkString)

//遍历的方式二,使用foreach逐行输出
//source.getLines()
//source.getLines().foreach(println)

//遍历的方式三,使用for遍历单个字符输出
for (c <- source2 ){ //逐个字符读取
println(c)
}

//使用完Source后,记得需要close
source.close()
source2.close()
}

}
  1. 第一个参数,可以是文件名或java.io.File
  2. 第二个参数,如果没有会使用当前平台缺省的字符编码
  3. source.getLines读取行,结果是一个迭代器可以转换成Array等
  4. 使用完Source后,记得需要close

从URL或其他源读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.xiaoxiaomo.demo.ch09

import scala.io.{BufferedSource, Source}

/**
* 从URL或其他源读取数据
* Created by xiaoxiaomo on 2016/4/5.
*/

object ReadOther {

//TEST
def main(args: Array[String]) {

//从URL中读取信息
//注意URL中的编码
var rL1: BufferedSource = Source.fromURL(
"http://blog.xiaoxiaomo.com/2016/04/02/Scala-%E7%BB%A7%E6%89%BF/")

//从String字符串中读取
val string: Source = Source.fromString("blog.xiaoxiaomo.com")
val str = string.getLines().mkString

//从Char中读取信息
Source.fromChar(str.charAt(2)) ;

//从Byte数组中读取信息
Source.fromBytes(new Array[Byte](100)) ;

}

}

读取词法单元和数字

在很多场景下,我们时常会遇到对读取的文件进行处理(切割,筛选等),然而我们可以读取文件后转为字符串,通过字符串的一个split方法进行切割。事例:现在我们项目跟目录有如下文件,然后我们使用相对路径读取,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.File
import scala.io.{Source, BufferedSource}

/**
* 根据正则读取词法单元
* Created by xiaoxiaomo on 2016/4/6.
*/

object ReadSqlit {

def main(args: Array[String]) {

//通过相对路径读取资源文件
val source = Source.fromFile(new File("test.txt"),"UTF-8")

//通过空格(正则表达式)切分成一个一个数据
val word = source.mkString.split("\\s+")

//遍历数据
for( w <- word ){
println(w)
}
}
}
  • 运行结果
1
2
3
4
5
23
2423
32
423
423

可以对切割后的文件进行处理,如下,转为Double

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.io.File

import scala.io.{BufferedSource, Source}

/**
* 切割后处理
* Created by xiaoxiaomo on 2016/4/6.
*/
object ReadSqlit2 {

def main(args: Array[String]) {
val source: BufferedSource = Source.fromFile(new File("test.txt"),"UTF-8")
val word = source.mkString.split("\\s+")

//转为Double
for( w <- word ) yield {
val double: Double = w.toDouble
println(double+ " ")
}

//或者通过另一种方式转换
val map: Array[Double] = word.map(_.toDouble)
for( m <- map ) {
print(m+ " - ")
}
}
}

  • 运行结果
1
2
3
4
5
6
23.0 
2423.0
32.0
423.0
423.0
23.0 - 2423.0 - 32.0 - 423.0 - 423.0 -

读取二进制文件

Scala没有提供读取二进制文件的方法,需要使用Java类库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.{File, FileInputStream}

/**
* 读取二进制文件
* Created by xiaoxiaomo on 2016/4/6.
*/

object InputStream {

def main(args: Array[String]) {
val file: File = new File("test.txt")
val in = new FileInputStream(file)

var c = 0 ;
while( c != -1 ){
c = in.read()
print(c.toChar)
}
in.close()
}
}

写入文件

Scala也没有对写入文件的内建支持,依旧可以使用Java类库来实现。如:

1
2
3
val out = new PrintWriter("numbers.txt")
for (i <- 1 to 100) out.println(i)
out.close()

但是在使用这里printf方法时,传递AnyVal(比如各种数字)类型给方法时,编译器会要求将其转换成

1
2
3
4
5
6
AnyRef
out.printf("%6d %10.2f", quantity.asInstanceOf[AnyRef],
price.asInstanceOf[AnyRef])

// 为了避免这个麻烦,可以使用String类的format方法
out.printf("%6d %10.2f".format(quantity, price))

访问目录

目前没有“正式的”用来访问目录中所有文件,或递归遍历所有目录的类。(本章各种没有内建没有正式是闹哪样啊!也无所谓了,用Java类库就是了。)下面探讨一下替代方案。
遍历某目录下所有子目录的函数:

1
2
3
4
5
import java.io.File
def subdirs(dir: File): Iterator[File] = {
val children = dir.listFiles.filter(_.isDirectory)
children.toIterator ++ children.toIterator.flatMap(subdirs _)
}

// 调用打印出所有的子目录

反/序列化

1
2
3
4
5
6
7
8
9
val fred = new Person(...)
import java.io._
val out = new ObjectOutputStream(new FileOutputStream("/tmp/test.obj"))
out.writeObject(fred)
out.close()

val in = new ObjectInputStream(new FileInputStream("/tmp/test.obj"))
val savedFred = in.readObject().asInstanceOf[Person]
in.close()

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器