Groovy开发套件-处理IO

http://groovy-lang.org/groovy-dev-kit.html

1.使用IO

Groovy提供了许多用于I / O 的 辅助方法。尽管您可以在Groovy中使用标准Java代码来处理这些代码,但Groovy提供了更便捷的方式来处理文件,流,读取器,...

您应该查看以下方法:

下一节重点介绍使用上面可用的辅助方法的示例惯用构造,但并不意味着对所有可用方法的完整描述。为此,请阅读GDK API

1.1 读取文件

作为第一个示例,让我们看看如何在Groovy中打印文本文件的所有行:

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

eachLine方法是FileGroovy自动添加到类的方法,并且具有许多变体,例如,如果您需要知道行号,则可以使用此变体:

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

如果出于任何原因在eachLine主体中引发了异常,则该方法将确保正确关闭资源。对于Groovy添加的所有I / O资源方法,都是如此。

例如,在某些情况下,您将更喜欢使用Reader,但是仍然可以从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运算符将文件的内容分成几行:

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

您需要将文件的内容放入byte[]多少次,并且需要多少代码?Groovy实际上非常容易:

byte[] contents = file.bytes

使用I / O不仅限于处理文件。实际上,很多操作都依赖于输入/输出流,因此,为什么Groovy会向这些流添加很多支持方法,如您在文档中所看到的 。

举个例子,你可以非常容易从File获取InputStream:

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

但是,您可以看到它需要您关闭输入流。在Groovy中,通常最好使用withInputStream惯用语为您解决这个问题:

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

1.2 写文件

当然,在某些情况下,您将不希望读取而是写入文件。选项之一是使用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()

但是,您会看到它需要您关闭输出流。同样,总的来说,使用withOutputStream惯用法来处理异常并在任何情况下关闭流都是一个更好的主意:

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

1.3 遍历文件树

在脚本编写上下文中,遍历文件树以查找某些特定文件并对其进行处理是一项常见的任务。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 ->
// 如果当前文件是目录,并且名称是bin,则停止遍历
if (file.directory && file.name=='bin') {
FileVisitResult.TERMINATE
} else {
// 否则,打印文件名并继续
println file.name
FileVisitResult.CONTINUE
}

}

1.4 数据与对象

在Java中,分别使用java.io.DataOutputStream和 java.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接口,则可以继续执行对象输出流,如下所示:

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
}

1.5 执行外部程序

上一节描述了在Groovy中处理文件,读取器或流有多么容易。但是,在诸如系统管理或开发人员之类的领域中,通常需要与外部流程进行通信。

Groovy提供了一种执行命令行过程的简单方法。只需将命令行写为字符串并调用该execute()方法即可。例如,在* nix机器(或安装了适当* nix命令的Windows机器)上,您可以执行以下命令:

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

该execute()方法返回一个java.lang.Process实例,该实例随后将允许处理输入/输出/错误流以及要检查来自进程的退出值等。

例如,这里是与上面相同的命令,但是我们现在一次处理一行结果:

def process = "ls -l".execute()             
process.in.eachLine { line ->               
    println line                            
}

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

请记住,许多命令是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提供了一些附加的辅助方法,这些方法使处理流程的流变得更加容易。

这是如何吞噬过程中的所有输出(包括错误流输出)的方法:

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

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

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,695评论 0 3
  • 本文参考自The Groovy Development Kit,一些代码直接引用了源文档。 Groovy开发工具包...
    乐百川阅读 3,272评论 0 4
  • Groovy :是一种动态语言。 1:这种语言比较有特点,它和 Java 一样,也运行于 Java 虚拟机中。简单...
    PeytonWu阅读 1,554评论 0 1
  • 一只调皮的猴子天天待在动物园里,它觉得很烦。因为它的调皮,不仅时常遭到妈妈的责备,是隔三岔五受到动物园管理员的打骂...
    秋天的丘阅读 850评论 0 50
  • 网新关键词 注意瞬脱需要一小段时间转移注意力,让思维重新定向,让精力集中,让大脑过滤掉无关的信息,从而实现主要任务...
    施传康阅读 355评论 0 0