天天看點

Kotlin學習(9)檔案I/O、正規表達式與多線程

1. 文件I/O操作

1.1 读文件

  1. readText:获取文件全部内容字符串

    如果想要简单的读取文件内容,则使用 readText(),可以返回整个文件内容

fun getFileContent(filename: String): String{
   val f = File(filename)
   return f.readText(Charset.forName("UTF-8"))
}      
  1. readLines:获取文件每行内容

    如果想要获取每行的内容,我们可以使用 split("\n")来获得一个每行内容的数组。

    我们也可以直接调用Kotlin封装好的readLines(),获取每行的内容:

fun getFileLines(filename: String): List<String> {
    return File(filename).readLines(Charset.forName("UTF-8"))
}      
  1. readBytes():读取字节流数组
//返回这个文件的字节数组
val bytes: ByteArray = f.readBytes()
println(bytes.joinToString(separator = " "))

//与Java互操作,直接调用Java中的InputStream
val reader: Read = f.reader()
val inputStream: InputStream = f.inputStream()
val bufferedReader: BufferedReader =  f.bufferedReader()      
  1. bufferedReader:获取文件的方法签名
fun File.bufferedReader(
   charset: Charset = Charsets.UTF_8
   bufferSize: Int = DEFAULT_BUFFER_SIZE
):      

1.2 写文件

使用Kotlin扩展的函数,写入文件也变得相当简单。我们可以写入字符串,也可以写入字节流,还可以直接调用Java的Writer或者OutputStream类,写文件通常分为​​

​覆盖写​

​​和​

​追加写​

​两种。

  1. writeText:覆盖写文件

    我们使用​​

    ​writeText()​

    ​直接向一个文件中写入字符串text的内容
fun writeFile(text: String, destFile: String) {
    val f = File(destFile)
    if(!f.exists()){
       f.createNewFile()
    }
    //覆盖写入文件内容
    f.writeText(text, Charset.defaultCharset())
}      
  1. appendFile: 末尾追加写文件

    使用​​

    ​appendFile()​

    ​ 向一个文件的末尾追加写入内容text
//追加文件内容
fun appendFile(text: String, destFile: String){
    val f = File(destFile)
    if(!f.exists()){
       f.createNewFile()
    }
    f.appendText(text, Charset.defaultCharset())
}      
  1. appendBytes: 追加写入字节数组

    追加字节数组到该文件的末尾追加写入内容text

fun File.appendBytes(array: ByteArray)      
  1. bufferedWriter: 获取缓存区写对象

    获取改文件的bufferedWrite()方法签名

fun File.bufferedWriter(
  charset: Charset = charsets.UTF-8
  bufferSize: Int = DEFAULT_BUFFER_SIZE
):      

1.3 遍历文件树

  1. walk:遍历文件树
fun traverseFileTree(filename: String) {
  val f = File(filename)
  val fileTreeWalk = f.walk()
  //遍历文件夹下面的所有文件的路径
  fileTreeWalk.iterator().forEach{ println(it.absolutePath) }
}

//遍历当前文件下所有的子目录文件,并将结果存入到一个 Iterator中
fun getFileIterator(filename: String): Iterator<File> {
   val f = File(filename)
   val fileTreeWalk = f.walk()
   return fileTreeWalk.iterator()
}

//我们遍历当前文件夹下的所有目录,还可以根据条件进行过滤
fun getFileSequenceBy(filename: String, p: (File) -> Boolean): Sequuence<File> {
  val f = File(filename)
  //根据条件p过滤
  return f.walk().fileter(p)
}      
  1. copyRecursively :递归复制文件

    复制改文件或者递归复制该目录及其所有子文件到指定路径下, 如果指定路径下的文件不存在,会自动创建。

fun File.copyRecursiverly(
    target: File,                   //目标文件
    overwrite: Boolean = false,     //是否覆盖。true:覆盖之前先删除原来的文件
    onError: (File, IOException) -> OnErrorAction = { _, exception -> throw exception }    //错误处理
)      

2. 网络I/O

根据URL获取该URL响应HTML函数:

fun getUrlContent(url: String): String{
    //获取该URL的响应HTML文本
    return URL(url).readText(Charset.defaultCharset())
}      

根据URL获取该URL响应比特数组函数:

fun getUrlBytes(url: String): ByteArray{
    return URL(url).readBytes()
}      

把URL响应字节数组写入文件中:

fun writeUrlBytesTo(filename: String, url: String){
   val bytes = URL(url).readBytes()
   File(filename).writeBytes(bytes)
}      

3. 执行Shell命令

在Groovy语言中,我们可以用Shell命令来执行I/O操作

首先我们来扩展 String的 ​​

​execute()​

​,让这个函数来实现Shell命令

//给String扩展 execute()函数
fun String.execute(): Process {         
    val runtime = Runtime.getRuntime()
    return runtime.exec(this) 
}

//然后给Process类扩展一个 text() 函数
fun Process.text(): String {
    var output = ""
    val inputStream = this.inputStream
    val isr = InputStreamReader(inputStream)
    var reader = BufferedReader(isr)
    var line: String? = ""
    while (line != null) {
       line = reader.readLine()
       output += line + "\n"
    }
    return output
}      

完成了上面两个简单函数的扩展后,就可以在下面的代码上测试 Shell命令:

val p = "ls".execute()

val exitCode = p.waitFor()
val text = p.text()

println(exitCode)
println(text)      

4. 正则表达式

我们在Kotlin中除了仍然可以使用 Java中的 Pattern、Matcher等类之外,Kotlin还提供了一个正则表达式类 kotlin\text\regex\Regex.kt,我们通过 Regex的构造函数来创建一个正则表达式。

4.1 构造Regex表达式

使用Regex构造函数如下:

//创建一个Regex对象,匹配的正则表达式是 [a-z]+
val r1 = Regex("[a-z]+") 

//RegexOption 是直接使用的Java类Pattern中的正则匹配选项
val r2 = Regex("[a-z]+", RegexOption.IGNORE_CASE)      

RegexOption 是直接使用的Java类Pattern中的正则匹配选项

使用String的 toRegex() 如下:

//直接使用Kotlin中给String扩展的toRegex函数
val r3 = "[A-Z]+".toRegex()      

4.2 Regex函数

  1. matches()

    如果输入的字符串全部匹配正则表达式则返回 true,否则返回false

val r1 = Regex("[a-z]+")
>>>r1.matches("ABCzxc")     //其中大写的ABC不匹配,则返回false
>false

val r2 = Regex("[a-z]+",RegexOption.IGNORE_CASE) //正则表达式,忽略大小
>>>r2.matches("ABCzxc")
>true

valr r3 = [A-Z]+".toRegex()
>>>r3.matches("123123")
>false      
  1. containsMatchIn()

    如果输入字符串中至少有一个匹配就返回 true,如果没有匹配就返回false

val r1 = Regex("[0-9]+")
>>>r1.containsMatchIn("012AAAE")
>true

>>>r1.containsMatchIn("asdad")
>false      
  1. matchEntire()

    如果输入的字符串全部匹配,则返回一个MacherMatchResult,否则返回null

val r1 = Regex("[0-9]+")
>>>r1.matchEntire("1234567890")  //全部满足条件
>kotlin.text.MacherMatchResult@xxxxxx
>>>r1.matchEntire("1234567890!")
>null

//我们可以访问MatcherMatchResult的value属性来获得匹配的值
//其中的使用了安全调用符,表明可以返回空值
>>>r1.matchEntire("1234567890")?.value
>1234567890      
  1. replace(input: CharSequence, replacement: String): String

    把输入的字符串中匹配的内容替换成 replacement的内容

val r1 = Regex("[0-9]+")
>>>r1.replace("12345XYZ","abcd")
//12345将被替换成abcd
>abcdXYZ      
  1. replace(input: CharSequence, transform:(MatchResult) -> CharSequence): String

    replace()的功能是把输入的字符串中匹配到的值,用函数​​

    ​transform()​

    ​ 映射之后的新值进行替换
val r1 = Regex("[0-9]+")
>>>r1.replace("1zxc2",{ (it.value.toInt() * it.value.toInt()).toString() })
//匹配到的数字开平方
>1zxc4      
  1. find()函数

    会返回第一个匹配的MatcherMatchResult对象。

val r1 = Regex("[0-9]+")
>>>r1.find("12314rsfiafp123asookf1`1")?.value()
>12314      
  1. findAll()

    返回所有匹配的MatcherMatchResult序列。

val r1 = Regex("[0-9]+")
val sequence = r1.findAll("123abc456def789gh")
>>>sequence
>kotlin.sequences.GeneratorSequence@xxxxx

>>>sequence.forEach{println(it.value)}
>123
>456
>789      

4.3 使用Java的正则表达式

在Kotlin中仍然可以使用Java正则表达式的API

val r1 = Regex("[0-9]+")
val p = r1.toPattern()
val m = p.matcher("123abc456")
while (m.find()) {
  val d = m.group()
  println(d)
}

>123
>456      

5. 多线程编程

5.1 创建线程

因为我们可以在Kotlin中使用Java的类,所以我们可以使用Java的方式创建一个线程:

  1. 用对象表达式创建一个线程
//用对象表达式创建一个线程
//object表达式
object : Thread() {
            override fun run() {
                sleep(1000)
                println("Hello")
            }
 }.start()      
  1. 使用Lambda表达式

    下面是如何将一个​​

    ​Runnable​

    ​传递给一个新创建的Thread实例:
Thread {
       Thread.sleep(1000)
       println("hi")
}.start()      
  1. 使用Kotlin封装的Thread()函数
//kotlin中的线程操作
thread(start = true, isDaemon = false, name = "HiThread", priority = 4) {
       sleep(1000)
       println("hi")
}      

5.2 同步方法和块

synchronized不是Kotlin中的关键字,它替换为 ​​

​@Synchronized​

​注解。Kotlin中的同步方法的声明如下:

@Synchronized
 fun appendFile(text: String, filename: String) {
        val f = File(filename)
        if (!f.exists()) {
            f.createNewFile()
        }
        f.appendText(text, Charset.defaultCharset())
 }      
fun appendFileSync(text: String, filename: String) {
        val f = File(filename)
        if (!f.exists()) {
            f.createNewFile()
        }

        synchronized(this) {
            f.appendText(text, Charset.defaultCharset())
        }
    }      
@Volatile
    var running = false

    fun start() {
        running = true
        thread(start = true) {
            while (running) {
                println("Start")
            }
        }
    }
    
    fun stop(){
        running = false;
        println("Stop")
    }