IO操作

Groovy为I/O操作提供了许多帮助方法,虽然你可以在Groovy中用标准Java代码来实现I/O操作,不过Groovy提供了大量的方便的方式来操作File、Stream、Reader等等。

读取文件

读取文本文件并打印每一行文本

new File(baseDir, 'haiku.txt').eachLine{ line ->
println line
}

eachLine方法是Groovy为File类自动添加的方法,同时提供多个变体方法,比如你想知道读取的行数,你可以使用它的变体方法,如下

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

如果出于某种原因eachLine抛出异常,该方法能够确保资源正确地关闭,这适用于所有Groovy添加的I/O资源方法

例如在某些情况下,你更喜欢使用Reader访问I/O资源,但你仍然受益于Groovy的自动资源管理。在下一个示例中,即使发生了异常,Reader也将会被关闭。

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

如果你需要收集文本文件的每一行到一个列表中,你可以这样做:

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

或者你甚至可以用as操作符来讲文件内容转为String数组

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

多少次你不得不获得一个文件的内容到一个byte[],它需要多少代码?Groovy使得这件事非常的容易。

byte[] contents = file.bytes

处理I/O并不局限于处理文件。事实上,很多的操作依赖于输入/输出流,这就是为什么Groovy添加大量的支持方法,正如你所看到的文档。

例如,你可以很容易从一个文件获得一个InputStream

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

但是你可以看到,这种方式需要你手动关闭流。会为你留意到,在Groovy中使用withInputStream通常是更好的方式。

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

写文件

当然,一些时候你并不想读取文件,而是要写文件。其中一个方式就是使用Writer:

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

但是对于这样一个简单的示例中,使用<<操作符就足够了:

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

当然我们并不总是处理文本内容,所以您可以使用Writer或者直接写入字节,例如:

file.bytes = [66,22,11]

当然你也可以直接处理输出流。例如,下面就是如何创建一个输出流写入一个文件:

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

但是你可以看到它需要你手动关闭输出流。会为你留意到,在Groovy中使用withOutputStream通常是更好的方式。

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

遍历文件树

在脚本中,在文件树种查找一些特定文件并处理这些文件是很常见的事情。Groovy提供了多种方法来做到这一点。例如你可以为一个文件夹中的每个文件直行一些操作:

//在目录的每一个文件直行闭包代码
dir.eachFile { file ->
println file.name
} //在目录中符合匹配模式的文件直行闭包代码
dir.eachFileMatch(~/.*\.txt/) { file ->
println file.name
}

通常你需要处理一个更深的目录结构的文件,这种情况下你可以使用eachFileRecurse

//在指定目录递归查找,并在每一个文件和目录直行闭包代码
dir.eachFileRecurse { file ->
println file.name
} //在指定目录递归查找,并在每一个文件直行闭包代码
dir.eachFileRecurse(FileType.FILES) { file ->
println file.name
}

对于更复杂的遍历技术可以使用traverse方法,它你需要设置一个特殊的标志指示这个遍历要做什么。

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

数据和对象

在Java中使用java.io.DataOutputStreamjava.io.DataInputStream进行序列化和反序列化并不少见,Groovy将使它更容易处理。例如,您可以把数据序列化到一个文件中并反序列化它使用以下代码:

boolean b = true
String message = 'Hello from Groovy'
// Serialize data into a file
file.withDataOutputStream { out ->
out.writeBoolean(b)
out.writeUTF(message)
}
// ...
// Then read it back
file.withDataInputStream { input ->
assert input.readBoolean() == b
assert input.readUTF() == message
}

类似的,如果您想要序列化的数据实现了Serializable接口,你可以将它作为一个Object输出流处理,例如:

Person p = new Person(name:'Bob', age:76)
// Serialize data into a file
file.withObjectOutputStream { out ->
out.writeObject(p)
}
// ...
// Then read it back
file.withObjectInputStream { input ->
def p2 = input.readObject()
assert p2.name == p.name
assert p2.age == p.age
}

执行外部程序

前一节中描述的是使用Groovy处理文件多么容易。然而在系统管理等领域或devops通常需要与外部processes沟通。Groovy提供了一个简单的方法来执行命令行processes。仅仅需要些命令字符串再调用execute()方法即可。如。在 *nix机(安装了合适的 *nix命令工具的windows机),你这样执行:

//在外部process执行`ls`命令
def process = "ls -l".execute()
//读取文本并打印
println "Found text ${process.text}"

execute()方法返回一个java.lang.Process对象,并允许处理它的in/out/err流和退出值,从Process检查等。

如,这是和上面一样的命令

//执行`ls`命令
def process = "ls -l".execute()
//遍历命令进程的输入流
process.in.eachLine { line ->
//打印每一行输入流
println line
}

值得注意的是,in是一个输入流,对应于命令的标准输出。 out指的是可以向Process发送数据的流(标准输入)。

记住许多命令是shell内置函数,需要特殊处理。所以,如果你想要在一个Windows机器上列出一个目录下的所有文件:

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

你会收到一个IOException说无法运行程序“dir”:CreateProcess error = 2,系统找不到指定的文件。这是因为dir内置在Windows shell(cmd.exe)中,不能作为简单的可执行文件运行。 相反,你需要写:

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

此外,由于此功能当前使用java.lang.Process底层,必须考虑该类的缺陷。尤其是,这个类的javadoc说:

由于一些本地平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子过程的输出流可能导致子过程阻塞甚至死锁

正因为如此,Groovy提供了一些额外的帮助方法,使得流处理更容易。

这里是如何从你的Process中gobble(未翻译)所有的输出(包括错误流输出):

def p = "rm -f foo.tmp".execute([], tmpDir)
p.consumeProcessOutput()
p.waitFor()

还有consumeProcessOutput的变体,使用StringBufferInputStreamOutputStream等...有关完整的列表,请阅读GDK API for java.lang.Process

此外,这些是一个pipeTo命令(映射到|以允许重载),它使一个进程的输出流被传送到另一个进程的输入流。

这里有一些使用的例子:

proc1 = 'ls'.execute()
proc2 = 'tr -d o'.execute()
proc3 = 'tr -d e'.execute()
proc4 = 'tr -d i'.execute()
proc1 | proc2 | proc3 | proc4
proc4.waitFor()
if (proc4.exitValue()) {
println proc4.err.text
} else {
println proc4.text
}

消耗错误

def sout = new StringBuilder()
def serr = new StringBuilder()
proc2 = 'tr -d o'.execute()
proc3 = 'tr -d e'.execute()
proc4 = 'tr -d i'.execute()
proc4.consumeProcessOutput(sout, serr)
proc2 | proc3 | proc4
[proc2, proc3].each { it.consumeProcessErrorStream(serr) }
proc2.withWriter { writer ->
writer << 'testfile.groovy'
}
proc4.waitForOrKill(1000)
println "Standard output: $sout"
println "Standard error: $serr"

Groovy系列(5)- Groovy IO操作的更多相关文章

  1. Java基础复习笔记系列 七 IO操作

    Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...

  2. Groovy系列-groovy比起Java--有哪些地方写起来更舒服?

    groovy比起java-有哪些地方写起来更舒服 java发展缓慢,语法落后冗余 说起java,其实java挺好的,java现在的性能也不错,但是,java的语法显然比较落后,而且冗余,getter/ ...

  3. Gradle系列之一 Groovy语法精讲

    Gradle技术之一 Groovy语法精讲 gradle脚本是基于groovy语言开发的,想要学好gradle必须先要对groovy有一个基本的认识 1. Groovy特点 groovy是一种DSL语 ...

  4. Pandas系列(十一)-文件IO操作

    数据分析过程中经常需要进行读写操作,Pandas实现了很多 IO 操作的API,这里简单做了一个列举. 格式类型 数据描述 Reader Writer text CSV read_ csv to_cs ...

  5. openssl之BIO系列之6---BIO的IO操作函数

    BIO的IO操作函数     ---依据openssl doc/crypto/bio/bio_read.pod翻译和自己的理解写成          (作者:DragonKing Mail:wzhah ...

  6. [.NET] 利用 async & await 进行异步 IO 操作

    利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html  序 上次,博主 ...

  7. python之协程与IO操作

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...

  8. Java IO系列之一:IO

    1. 概述 Java IO一般包含两个部分: 1.java.io包中堵塞型IO: 2.java.nio包中的非堵塞型IO,通常称为New IO. java.io包下,分为四大块近80个类: 1.基于字 ...

  9. 重叠io操作

    第一章 一. 重叠模型的优点 1. 可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口只是支持NT系统. 2. 比起阻塞.select.WSAAsyncSelect以及WSAEv ...

随机推荐

  1. [WPF] 使用 MVVM Toolkit 构建 MVVM 程序

    1. 什么是 MVVM Toolkit 模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式. 借助 MVVM,可以在 XAML 中以声明方式定义 UI ...

  2. unserialize反序列化 安鸾 Writeup

    关于php反序列化漏洞原理什么,可以看看前辈的文章: https://xz.aliyun.com/t/3674 https://chybeta.github.io/2017/06/17/浅谈php反序 ...

  3. redis和memecache有什么区别?

    1.memcache所有值均是简单地字符串,redis有复杂的数据类型. 2.memcache不支持数据持久化,redis支持数据持久化. 3.redis速度比memcache快,redis构建了自己 ...

  4. docker harbor安装

    # 官网下载离线包,https://github.com/goharbor/harbor/releases src]# tar xf harbor-offline-installer-v1.8.3.t ...

  5. Flink Data transformation(转换)

    Flink Data transformation 算子学习 1.Source:数据源,Flink在流处理和批处理上的source大概有4类: 基于本地集合的source.基于文件的source.基于 ...

  6. C# 使用正则表达式替换PPT中的文本(附vb.net代码)

    文本介绍如何在C#程序中使用正则表达式替换PPT幻灯片中的指定文本内容.具体操作步骤如下: 1. 在程序中引用Spire.Presentation.dll.两种方法可参考如下: (1)直接在程序中通过 ...

  7. rabbitMq镜像集群

    rabbitMq延迟投递的方案 1 把消息记录到数据路,通过定时器进行刷新 2 TTL 加上死信队列 :通过路由把过期的消息同步到死信队列,通过死信队列的消费者进行消费 3

  8. java js转码解码

    摘自网友:https://blog.csdn.net/sgear/article/details/1509400?utm_medium=distribute.pc_relevant.none-task ...

  9. new Vue({ render: h => h(App), }).$mount('#app')

    这里创建的vue实例没有el属性,而是在实例后面添加了一个$mount('#app')方法. $mount('#app') :手动挂载到id为app的dom中的意思 当Vue实例没有el属性时,则该实 ...

  10. Promise.race()

    Promise.race([ ])---race竞赛,只要有一个决议了,就返回一个promise实例(对应resolve()或reject( )中参数值: 1.与Promise.all()对应的,还有 ...