Groovy开发工具包

来源:互联网 发布:matlab 最优化算法 书 编辑:程序博客网 时间:2024/06/10 17:20

本文参考自The Groovy Development Kit,一些代码直接引用了源文档。

Groovy开发工具包(The Groovy Development Kit)的名字一开始迷惑了我,我以为是一些IDE的插件之类的。在实际看了原文档之后,我才明白这是Groovy提供的一组类库和方法,让我们开发更加方便。

IO功能

在Java中读写文件非常麻烦。由于JDK类库设计问题,以及Java本身的局限性,导致Java自带的功能很不好用。比如说Java的读写流,使用了装饰器设计模式,原意是让我们能够自行组合各种流,实现功能。但是实际情况是这让类库变得很复杂,我们哪怕是简单读写文件也需要声明一个很长的嵌套流。

Groovy为JDK的很多类提供了很多助手方法,让文件读写变得异常简单。列举如下。如果需要查看完整的GDK文档,可以查看GDK API文档。

  • the java.io.File class : http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html
  • the java.io.InputStream class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html
  • the java.io.OutputStream class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.html
  • the java.io.Reader class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Reader.html
  • the java.io.Writer class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Writer.html
  • the java.nio.file.Path class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/nio/file/Path.html

读取文件

Groovy提供了非常方便的文件读写方式。而且在使用withXXX方法或者闭包中抛出异常时,Groovy会自动关闭文件资源。所以我们可以放心的使用这些API。首先来看看文件读取。

Groovy为我们提供了丰富的功能。如果只需要简单读一个文件,简单的几行代码就可以做到。这些方法很简单,看代码就能知道怎么用。

    static void readingFiles() {        def baseDir = /C:\Windows\System32\drivers\etc/        def filename = 'hosts'        //读取文件        def file = new File(baseDir, filename)        file.eachLine {            println(it)        }        //同时获取行号        file.eachLine { line, num ->            println("line $num:$line")        }        //获取字节流        byte[] contents = file.bytes        println(contents.join(''))        //获取行列表        String[] lines = file.collect { it }        println(lines.join('\n'))        //将文件用作输入流        file.withInputStream {            //在这里执行操作        }    }

写入文件

写文件和读文件一样简单。我们可以使用Writer来写文件。文件编码可以不指定,默认是UTF-8。

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') << '这是一段文字'

还可以直接写入文件的字节流。

file.bytes = [66,22,11]

同样的,可以直接操作输出流,使用withXXX方法可以在闭包结束之后就自动关闭资源。

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

遍历文件树

遍历文件树也很简单。首先来看看遍历目录。

def dir = new File('C:\\Windows')//列出所有文件dir.eachFile {    if (it.isFile()) {        println(it)    }}//列出所有可执行文件dir.eachFileMatch(~/.*\.exe$/){    println(it)}

递归遍历也很简单,使用eachFileRecurse方法即可,还可以像方法传递枚举变量指定要递归的类型。

dir.eachFileRecurse { file ->                          println file.name}dir.eachFileRecurse(FileType.FILES) { file ->          println file.name}

traverse方法提供了更强大的功能,该方法还可以接受一个Map作为遍历参数,详细参数作用参见这里。

dir.traverse { file ->    if (file.directory && file.name=='bin') {        FileVisitResult.TERMINATE                       } else {        println file.name        FileVisitResult.CONTINUE                        }}

序列化对象

在Groovy中序列化和反序列化对象同样简单,直接看代码。

    static void serializeObjects() {        def person = new Person(id: 1, name: 'yitian', birthday: LocalDate.now())        def file = new File(getCurrentDir(), 'obj.txt')        file.withObjectOutputStream { it.writeObject(person) }        def obj        file.withObjectInputStream { obj = it.readObject() }        println(obj)    }class Person implements Serializable{    int id    String name    LocalDate birthday    @Override    String toString() {        "Person(id=$id,name=$name,birthday=$birthday"    }}

执行外部进程

在Grooy中调用外部进程也很简单。在字符串上面调用execute方法,然后就会返回一个java.lang.Process对象。

    static void executeExternalProcess() {        //列出文件        def userDir = System.properties['user.dir']        def process = "cmd /c dir ${userDir}".execute()        println "${process.text}"    }

要连接到进程的输入输出流也很简单,直接引用进程的in、out、err属性即可。需要注意in是输出流,out、err是输入流。

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

进程也支持各种高级操作,例如管道。我们只要调用进程的pipeTo方法,或者使用管道操作符,都可以使用管道。其他进程的使用方法请参见Groovy文档。

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

集合操作

Groovy开发工具包提供了方便的集合操作,这些操作类似Java 8的流类库,C#的LINQ,Kotlin的集合库,提供了各种方便的功能。

列表操作

列表上定义了丰富的操作,求和、排序、取值、集合运算等等。直接看代码吧。

    static void lists() {        println('列表')        //定义列表        def list = [1, 3, 25, 77, 5, 8, 97, 34, 100, 230]        //访问列表        println(list[2])        list[1] = 100        println(list[2..-1])        //添加元素        list << 77        list << 45        list.add(12)        list.addAll([1, 2, 3, 4, 5])        list += 5        println(list)        //删除元素        list - 77        //删除下标为6的元素        list.remove(6)        list.removeAll([1, 2, 3, 4, 5])        list -= 5        println(list)        //列表排序        list.sort().reverse()        println(list)        //断言        assert ![]        assert list        //迭代        list.each { print("$it ") }        println()        //带序号迭代        list.eachWithIndex { int e, int index -> print("$index->$e ") }        println()        //转换列表        def multi2 = list.collect { it * 2 }        println(multi2)        //和上面等价        def times2 = list*.multiply(2)        println(times2)        //过滤列表        def greaterThan17 = list.findAll { it > 7 }        println(greaterThan17)        //只查找第一个        def firstGreaterThan7 = list.find { it > 7 }        println(firstGreaterThan7)        //判断列表        assert !list.every { it > 100 }        assert list.any { it > 100 }        //求和和最值        def sum = list.sum()        println("sum=$sum")        println("max=${list.max()}")        println("min=${list.min()}")        //连接操作        println([1, 2, 3, 4].join('<->'))        //累积操作,累加、累乘还有更复杂的操作        println("累计求和:${[1, 2, 3, 4].inject { s, i -> s + i }}")        println("累计求积:${[1, 2, 3, 4].inject { s, i -> s * i }}")        //集合操作        def list1 = [1, 2, 3, 4]        def list2 = [2, 3, 5, 4, 23, 2]        println("求交:${list1.intersect(list2)}")        println("2出现了几次:${list2.count(2)}")        println("有几个奇数:${list2.count { it % 2 != 0 }}")        //无相交元素        assert [1, 2, 3].disjoint([4, 5, 6])        //重复元素        println("[1,2]重复两遍是什么:${[1, 2] * 2}")        println("[1,2]重复4遍是什么:${[1, 2].multiply(4)}")    }

Map操作

Map同样支持很多操作。直接看代码吧。

    static void maps() {        println("Map")        def map = [:]        //添加元素        map[7] = 7        map.put(8, 8)        (1..6).each { map[it] = it }        //遍历元素        println(map)        map.each { entry -> println("key:$entry.key,value:$entry.value") }        map.eachWithIndex { Map.Entry<Object, Object> entry, int index ->            println("index:$index,key:$entry.key,value:$entry.value")        }        map.each { key, value ->            println("key:$key,value:$value")        }        //集合        println("keys:${map.keySet()}")        println("entries:${map.entrySet()}")        println("values:${map.values()}")        //分组        def list = [1, 2, 3, 4, 5, 6]        def group = list.groupBy { it % 2 == 0 }        println("分组后的结果:$group")        //获取字符串键值        def couples = [amy: 'leo', king: 'lily', smith: 'lisa']        println(couples['king'])        println(couples.smith)        //字符串键要特别注意        def name = 'yitian'        def people = [name: 24]        println(people)        //使用括号才能正确将变量的值用作键        people = [(name): 24]        println(people)        //不要用GString作为键,它和String的哈希值不同        def s = '1234'        def gs = "${s}"        println("GString hash:${gs.hashCode()},String hash:${s.hashCode()}")        //放进去再用String取是读不出来的        def m = [(gs): 123]        assert m[s] == null    }

范围操作

范围操作是另一类方便的操作。我们可以定义闭区间和开闭区间,然后方便的迭代和判断范围。

    static void ranges() {        def range = 1..10        println(range)        //开闭区间        def range2 = 1..<10        range2.each { print "$it " }        println()        //范围的起止        println("起:${range.from},止:${range.to}")        //范围继承了List接口        assert range instanceof List        println("第二个和最后第二个元素:${range[1, -2]}")        println("第二个到倒数第二个:${range[1..-2]}")        println("3是否在范围内:${3 in range}")        //范围可用于switch        def marriedYears = 15        switch (marriedYears) {            case 1..5:                println("小夫妻")                break            case 6..10:                println("老夫妻")                break            case 11..30:                println("老夫老妻")                break            default:                println("成仙了")        }    }

操作符

Groovy还提供了切片操作符、展开操作符和星点操作符,对集合执行不同的操作。

    static void operators() {        //切片运算符        def list = 1..100        println("倒数十个元素:${list[-10..-1]}")        //展开运算符,也就是将两个集合展开合并为一个        def list2 = [1, 2, 3, *(4..10)]        println(list2)        //星点操作符,用于选定一个集合中的某个属性        def people = [[name: 'yitian'], [name: 'zhang3'], [name: 'li4']]        println("所有名字是:${people*.name}")    }

Groovy还为提供了扩展的方法,详细情况请参见相应文档。

  • 添加到Iterable的方法可以在后面的链接中找到here
  • 添加到Iterator的方法可以在后面的链接中找到here
  • 添加到Collection的方法可以在后面的链接中找到here
  • 添加到List的方法可以在后面的链接中找到here
  • 添加到Map的方法可以在后面的链接中找到here
0 0