使用Groovy开发之I/O

Groovy提供了一些辅助方法来帮助开发者开发I/O程序,开发过程中你可以使用标准的java代码,但Groovy提供了更多简便的方法来处理files、streams、readers,一起来看一下。

1、读取文件

def baseDir = "/Users/jiangxiaoma/Documents"
new File(baseDir, 'test.txt').eachLine { line ->
    println line
}

eachLine方法是被Groovy自动添加到File类的方法并有不同版本,比如要加上行号,你可以这样:

new File(baseDir, 'test.txt').eachLine { line, nb ->
    println "Line $nb: $line"
}

eachLine闭包内发生任何异常,该方法都能确保源文件被正常关闭。

在某些情况下你可能使用Reader,你仍将从Groovy的自动资源管理中获益,下面的例子,如果发生异常,reader将自动被关闭:

def count = 0, MAXSIZE = 3
new File(baseDir,"test.txt").withReader { reader ->
    while (reader.readLine()) {
        if (++count > MAXSIZE) {
            throw new RuntimeException('Test.txt should only have 3 verses')
        }
    }
}

如果你想把文件内容各行放进一个list,你可以这样:

def list = new File(baseDir, 'test.txt').collect {it}

或者你可以使用as将文件内容放入一个array:

def array = new File(baseDir, 'test.txt') as String[]

如果想把文件内容直接放进一个byte[],可以这样:

def file = new File(baseDir, 'test.txt')
byte[] contents = file.bytes

在进行I/O操作的时候不仅限于文件,事实上,很多操作都依赖于输入输出流,下面例子是从File中获取InputStream

def is = new File(baseDir,'test.txt').newInputStream()
// do something ...
is.close()

这种方式需要自己手动关闭流,使用withInputStream方法将会自动关闭流:

new File(baseDir,'haiku.txt').withInputStream { stream ->
// do something ...
}

2、写入文件

在某些情况下,你可能不仅需要读取文件,也要写入文件,写入文件使用Writer

new File(baseDir,'test.txt').withWriter('utf-8') { writer ->
    writer.writeLine 'Into the ancient pond'
    writer.writeLine 'A frog jumps'
    writer.writeLine 'Water’s sound!'
}

更简单的方法是使用<<操作符:

new File(baseDir,'test.txt') << '''Into the ancient pond
    A frog jumps
    Water’s sound!'''

如果你的test.txt里有内容,上面两种方式将会覆盖test.txt的内容。

当然你也可以直接用输出流来写入文件:

def os = new File(baseDir,'data.bin').newOutputStream()
// do something ...
os.close()

同样的,withOutputStream方法将自动关闭输出流和处理异常:

new File(baseDir,'data.bin').withOutputStream { stream -> 
// do something ...
}

3、遍历文件树

遍历文件夹是一个经常用到的功能,Groovy提供了一些方法来遍历,比如列出根目录下的所有文件和文件夹、找到符合正则表达式的标题的文件:

def dir = new File("/")
//eachFile()方法返回该目录下的所有文件和子目录,不递归
dir.eachFile { file ->
    println file.name
}
dir.eachFileMatch(~/.*\.txt/) {file ->
    println file.name
}

可能你需要处理更深目录层次的文件,或者只显示文件或者文件夹,你可以使用eachFileResource

def dir = new File("/")
//dir.eachFileRecurse()方法会递归显示该目录下所有的文件和目录
dir.eachFileRecurse { file ->
    println file.name
}
dir.eachFileRecurse(FileType.FILES) { file ->
    println file.name
}

一些更复杂的遍历方法你可以使用traverse方法,但需要你设置一个特殊的标志指示如何遍历:

dir.traverse { file ->
    //如果当前文件是一个目录且名字是bin,则停止遍历
    if (file.directory && file.name=='bin') {
        FileVisitResult.TERMINATE
    //否则打印文件名字并继续
    } else {
        println file.name
        FileVisitResult.CONTINUE
   }
}

4、数据和类的序列化&反序列化

在java中使用java.io.DataOutputStreamjava.io.DataInputStream进行序列化和反序列化是非常常用的,使用Groovy将使之变得更容易,下面是序列化数据到文件和从文件读取数据进行反序列化:

boolean b = true
String message = 'Hello from Groovy'
def file = new File(baseDir, 'test.txt')
// 序列化数据到文件
file.withDataOutputStream { out ->
    out.writeBoolean(b)
    out.writeUTF(message)
}
// ...
// 从文件读取数据并反序列化
file.withDataInputStream { input ->
    assert input.readBoolean() == b
    assert input.readUTF() == message
}

同样的,如果一个类实现了Serializable接口,可以将对象序列化到文件:

def file = new File(baseDir, 'test.txt')
Person p = new Person(name:'Bob', age:76)
// 序列化对象到文件
file.withObjectOutputStream { out ->
    out.writeObject(p)
}
// ...
// 从文件读取数据进行反序列化
file.withObjectInputStream { input ->
    def p2 = input.readObject()
    assert p2.name == p.name
    assert p2.age == p.age
}

5、程序中执行shell命令

Groovy提供了简单的方法执行shell命令:

def process = "ls -l".execute()
println "Found text ${process.text}"

//逐行处理
def process = "ls -l".execute()
process.in.eachLine { line ->
    println line
}

execute()方法返回了一个java.lang.Process实例。

如果想执行windows下的dir命令:

def process = "dir".execute()
println "${process.text}"

将返回IOExcepton异常:“Cannot run program "dir": CreateProcess error=2, The system cannot find the file specified.
这是因为dir命令是windows下的shell命令(cmd.ext),不能执行,应该这样写:

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,639评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,781评论 6 342
  • ———形式上跟随潮流,内容上跟随理想 今天看到了两句话,感觉特别震撼。“给客户想要的东西,比给客户事实更能赚钱” ...
    好奇动物阅读 866评论 0 1
  • 天亮了,推开窗,几只鸟儿在唱歌,听得出那是欢乐的歌曲。眼前的景色大不一样了。十年前,眼前的景色是一片多姿多彩的菜地...
    Sunshine陈阅读 249评论 0 0
  • 文/闲云野鹤秋锦 是命运的安排 还是纯粹的偶然 你我相逢于街道 你不认识我 我不认识你 你我相逢在路上 日日相见却...
    东丰闲云野鹤阅读 259评论 0 0