(2.2.9.4)grovy脚本类、文件 I/O 和 XML 操作
最后,我们来看一下 Groovy 中比较高级的用法。 脚本类1.脚本中 import 其他类 Groovy 中可以像 Java 那样写 package,然后写类。比如在文件夹 com/cmbc/groovy/目录中放一个文件,叫 Test.groovy,如图 10 所示:
你看,图 10 中的 Test.groovy 和 Java 类就很相似了。当然,如果不声明 public/private 等访问权限的话,Groovy 中类及其变量默认都是 public 的。 现在,我们在测试的根目录下建立一个 test.groovy 文件。其代码如下所示: 你看,test.groovy 先 import 了 com.cmbc.groovy.Test 类,然后创建了一个 Test 类型的对象,接着调用它的 print 函数。 这两个 groovy 文件的目录结构如图 12 所示: 在 groovy 中,系统自带会加载当前目录/子目录下的 xxx.groovy 文件。所以,当执行 groovy test.groovy 的时候,test.groovy import 的 Test 类能被自动搜索并加载到。 2.脚本到底是什么 Java 中,我们最熟悉的是类。但是我们在 Java 的一个源码文件中,不能不写 class(interface 或者其他....),而 Groovy 可以像写脚本一样,把要做的事情都写在 xxx.groovy 中,而且可以通过 groovy xxx.groovy 直接执行这个脚本。这到底是怎么搞的? 既然是基于 Java 的,Groovy 会先把 xxx.groovy 中的内容转换成一个 Java 类。比如: test.groovy 的代码是: println 'Groovy world!' Groovy 把它转换成这样的 Java 类: 执行 groovyc -d classes test.groovy groovyc 是 groovy 的编译命令,-d classes 用于将编译得到的 class 文件拷贝到 classes 文件夹下 图 13 是 test.groovy 脚本转换得到的 java class。用 jd-gui 反编译它的代码: 图 13 中:
groovyc 是一个比较好的命令,读者要掌握它的用法。然后利用 jd-gui 来查看对应 class 的 Java 源码。 3.脚本中的变量和作用域 前面说了,xxx.groovy 只要不是和 Java 那样的 class,那么它就是一个脚本。而且脚本的代码其实都会被放到 run 函数中去执行。那么,在 Groovy 的脚本中,很重要的一点就是脚本中定义的变量和它的作用域。举例: def x = 1 <==注意,这个 x 有 def(或者指明类型,比如 int x = 1) def printx(){ println x } printx() <==报错,说 x 找不到 为什么?继续来看反编译后的 class 文件。 图 14 中:
那么,如何使得 printx 能访问 x 呢?很简单,定义的时候不要加类型和 def。即: x = 1 <==注意,去掉 def 或者类型 def printx(){ println x } printx() <==OK 这次 Java 源码又变成什么样了呢? 图 15 中,x 也没有被定义成 test 的成员函数,而是在 run 的执行过程中,将 x 作为一个属性添加到 test 实例对象中了。然后在 printx 中,先获取这个属性。 注意,Groovy 的文档说 x = 1 这种定义将使得 x 变成 test 的成员变量,但从反编译情况看,这是不对得..... 虽然 printx 可以访问 x 变量了,但是假如有其他脚本却无法访问 x 变量。因为它不是 test 的成员变量。 比如,我在测试目录下创建一个新的名为 test1.groovy。这个 test1 将访问 test.groovy 中定义的 printx 函数: 这种方法使得我们可以将代码分成模块来编写,比如将公共的功能放到 test.groovy 中,然后使用公共功能的代码放到 test1.groovy 中。 执行 groovy test1.groovy,报错。说 x 找不到。这是因为 x 是在 test 的 run 函数动态加进去的。怎么办? import groovy.transform.Field; //必须要先 import @Field x = 1 <==在 x 前面加上@Field 标注,这样,x 就彻彻底底是 test 的成员变量了。 查看编译后的 test.class 文件,得到: 这个时候,test.groovy 中的 x 就成了 test 类的成员函数了。如此,我们可以在 script 中定义那些需要输出给外部脚本或类使用的变量了! 文件 I/O 操作本节介绍下 Groovy 的文件 I/O 操作。直接来看例子吧,虽然比 Java 看起来简单,但要理解起来其实比较难。尤其是当你要自己查 SDK 并编写代码的时候。 整体说来,Groovy 的 I/O 操作是在原有 Java I/O 操作上进行了更为简单方便的封装,并且使用 Closure 来简化代码编写。主要封装了如下一些了类: 1.读文件 Groovy 中,文件读操作简单到令人发指: def targetFile = new File(文件名) <==File 对象还是要创建的。 然后打开http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html def ism = targetFile.newInputStream() //操作 ism,最后记得关掉 ism.close 4 使用闭包操作 inputStream,以后在 Gradle 里会常看到这种搞法 targetFile.withInputStream{ ism -> 操作 ism. 不用 close。Groovy 会自动替你 close } 确实够简单,令人发指。我当年死活也没找到 withInputStream 是个啥意思。所以,请各位开发者牢记 Groovy I/O 操作相关类的 SDK 地址: java.io.File:http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html 2.写文件 和读文件差不多。不再啰嗦。这里给个例子,告诉大家如何 copy 文件。 def srcFile = new File(源文件名) def targetFile = new File(目标文件名) targetFile.withOutputStream{ os-> srcFile.withInputStream{ ins-> os << ins //利用 OutputStream 的<<操作符重载,完成从 inputstream 到 OutputStream //的输出 } } 尼玛....关于 OutputStream 的<<操作符重载,查看 SDK 文档后可知: 再一次向极致简单致敬。但是,SDK 恐怕是离不开手了... XML 操作除了 I/O 异常简单之外,Groovy 中的 XML 操作也极致得很。Groovy 中,XML 的解析提供了和 XPath 类似的方法,名为 GPath。这是一个类,提供相应 API。关于 XPath,请脑补<a rel="nofollow" href="https://en.wikipedia.org/wiki/XPath" "="" style="box-sizing: border-box; color: rgb(45,202); text-decoration: none; background-color: transparent;">https://en.wikipedia.org/wiki/XPath。 GPath 功能包括:给个例子好了,来自 Groovy 官方文档。 test.xml 文件: <response version-api="2.0"> <value> <books> <book available="20" id="1"> <title>Don Xijote</title> <author id="1">Manuel De Cervantes</author> </book> <book available="14" id="2"> <title>Catcher in the Rye</title> <author id="2">JD Salinger</author> </book> <book available="13" id="3"> <title>Alice in Wonderland</title> <author id="3">Lewis Carroll</author> </book> <book available="5" id="4"> <title>Don Xijote</title> <author id="4">Manuel De Cervantes</author> </book> </books> </value> </response>
//第一步,创建 XmlSlurper 类 def xparser = new XmlSlurper() def targetFile = new File("test.xml") //轰轰的 GPath 出场 GPathResult gpathResult = xparser.parse(targetFile) //开始玩 test.xml。现在我要访问 id=4 的 book 元素。 //下面这种搞法,gpathResult 代表根元素 response。通过 e1.e2.e3 这种 //格式就能访问到各级子元素.... def book4 = gpathResult.value.books.book[3] //得到 book4 的 author 元素 def author = book4.author //再来获取元素的属性和 textvalue assert author.text() == ' Manuel De Cervantes ' 获取属性更直观 author.@id == '4' 或者 author['@id'] == '4' 属性一般是字符串,可通过 toInteger 转换成整数 author.@id.toInteger() == 4 好了。GPath 就说到这。再看个例子。我在使用 Gradle 的时候有个需求,就是获取 AndroidManifest.xml 版本号(versionName)。有了 GPath,一行代码搞定,请看: def androidManifest = new XmlSlurper().parse("AndroidManifest.xml") println androidManifest['@android:versionName'] 或者 println androidManifest.@'android:versionName' (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |