快学Scala第9章----文件和正则表达式

本章要点

  • Source.fromFile(...).getLines.toArray 输出文件文件的所有行
  • Source.fromFile(...).mkString 以字符串形式输出文件内容
  • 将字符串转换为数字,可以用toInt或toDouble方法
  • 使用Java的PrintWriter来写入文本文件- “正则”.r 是一个Regex对象
  • 如果你的正则表达式包含反斜杠或引号的话,用"""..."""
  • 如果正则模式包含分组,你可以使用如下语法来提取它们的内容 for (regex(变量1, ..., 变量n) <- 字符串)

读取行

使用scala.io.Source 对象的getLines方法

import scala.io.Source
val source = Source.fromFile("myfile.txt", "UTF-8")
val lineIterator = source.getLines
for (line <- lineIterator) println(line)

// 或者将这些行放到数组或数组缓冲
val lines = source.getLines.toArray

// 使用完毕后关闭Source对象
source.close

读取字符

直接把source对象当做迭代器来从文件中读取单个字符:

for (c <- source)  处理c

source对象的buffered方法可以获得一个BufferedIterator[A]迭代器,使用它的head方法可以查看下一个字符,但不会把它当做以处理的字符:

import scala.io.Source
val source = Source.fromFile("myfile.txt", "UTF-8")
val iter = source.buffered
while (iter.hasNext) {
    if (iter.head 是符合预期的) {
        处理 iter.next
    } else {
         iter.next
         ...
    }
}

source.close

注意: 在else分之必须有iter.next或者while循环中有跳出循环的语句,否则将很可能陷入死循环。
如果文件不大,也可以读取成字符串处理:

val contents = source.mkString

读取词法单元和数字

val tokens = source.mkString.split("\\s+")  // 以空格隔开的词法单元

// 转换成Double类型
val numbers = for (w <- tokens) yield w.toDouble
// 或者
val numbers = tokens.map(_.toDouble)

从控制台读取数字

print ("How old are you? ")
val age = readInt()  // readLong or readDouble  这种方法假定了下一行输入只包含单个数字,
                             // 且前后没有空格,否则会抛出异常:NumberFormatException

从URL或其他源读取

val source1 = Source.fromURL("http://horstamnn.com", "UTF-8")
val source2 = Source.fromString("Hello, World")
val source3 = Source.stdin
...
source1.close
source2.close
source3.close

读取二进制文件

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

val file = new File(filename)
val in = new FileInputStream(file)
val bytes = new Array[Byte] (file.length.toInt)
in.read(bytes)
in.close

写入文本文件

Scala同样没有内建的对写入文件的支持,需要使用java.io.PrintWriter:

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

PrintWrite的printf方法比较特殊,需要你将参数转换成AnyRef才可以:

out.printf("%6d %10.2f", quantity.asInstanceOf[AnyRef], price.asInstanceOf[AnyRef])

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

访问目录

目前Scala没有正式的用来访问某个目录中的所有文件,或者递归的遍历所有目录。

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(dir)) 处理 d

序列化

在Java中,我们用序列化来将对象传输到其他虚拟机,或者临时存储。

// Java
public class Person implements java.io.Serializable {
    private static final long serialVersionUID = 42L;
    ...
}

// Scala
@SerialVersionUID(42L) class Person extends Serializable

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]

Scala的集合类都是可序列化的,因此你可以把它们用做你的可序列化类成员:

class Person extends Serializable {
    private val friends = new ArrayBuffer[Person]
    ...
}

正则表达式

使用scala.util.matching.Regex类

val numPattern = "[0-9]".r

val wsnumwsPattern = """\s+[0-9]\s""".r  // 处理反斜杠或引号

// findAllIn方法返回遍历所有匹配项的迭代器
for (matchString <- numPattern.findAllIn("99 bottles, 98 bottles")) 处理matchString

// 将迭代器转换为数组
val matches = numPattern.findAllIn("99 bottles, 98 bottles")).toArray   // Array(99, 98)

// 找到字符串的首个匹配项:
val m1 = wsnumwsPattern .findFirstIn("99 bottles, 98 bottles")  // Some(" 98 ")

// 检查是否某个字符串的开始部分能匹配
numPattern.findPrefixOf("99 bottles, 98 bottles")     // Some(99)
wsnumwsPattern .findPrefixOf("99 bottles, 98 bottles") // None

// 替换
numPattern.replaceFirstIn("99 bottles, 98 bottles", XX)  // "XX bottles, 98 bottles"
 numPattern.replaceAllIn("99 bottles, 98 bottles", XX)    // "XX bottles, XX bottles"

正则表达式组

分组可以让我们方便的获取正则表达式的子表达式。要提取的子表达式两侧加上圆括号,例如:

val numitemPattern = "([0-9]+) ([a-z]+)".r
// 要匹配组,可以把正则表达式对象当做"提取器"使用
val numitemPattern(num, item) = "99 bottles"  // 将num设为"99", item设为"bottles"

for (numitemPattern(num, item) <- numitemPattern.findAllIn("99 bottles, 98 bottls")) {
    处理num和item
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容