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
): BufferedReader

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
): BufferedWriter

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())
 }

所以注解 @Synchronized和Java中的 synchronized有着一样的效果
对于同步块,我们使用synchronized函数,它使用锁作为参数:

fun appendFileSync(text: String, filename: String) {
        val f = File(filename)
        if (!f.exists()) {
            f.createNewFile()
        }

        synchronized(this) {
            f.appendText(text, Charset.defaultCharset())
        }
    }

5.3 可变字段
同样地,Kotlin中没有 volatile关键字,但是有 @Volatile 注解

    @Volatile
    var running = false

    fun start() {
        running = true
        thread(start = true) {
            while (running) {
                println("Start")
            }
        }
    }
    
    fun stop(){
        running = false;
        println("Stop")
    }
发布了248 篇原创文章 · 获赞 99 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/rikkatheworld/article/details/103005296
今日推荐