第15章 Kotlin 文件IO操作與多線程
《Kotlin極簡教程》正式上架:
點擊這里 > 去京東商城購買閱讀
點擊這里 > 去天貓商城購買閱讀
非常感謝您親愛的讀者,大家請多支持K痢N诙省窟扑!有任何問題赋除,歡迎隨時與我交流~
我們在使用 Groovy 的文件 IO 操作的時候账劲,感覺非常便利戳护。同樣的Kotlin也有好用的文件 IO 操作的 API。同樣的在 Kotlin 中對 Java 的正則表達式功能做了一些實用的擴展瀑焦。還有 Kotlin 中的多線程主要也是對 Java 的多線程 API 作了一些封裝腌且。因為這些 Java 已經(jīng)有了很多的基礎(chǔ) API,Kotlin 并沒有自己再去重復(fù)實現(xiàn)榛瓮,而是在 Java 的基礎(chǔ)上進行了實用的功能擴展铺董。
本章我們就來介紹Kotlin 文件 IO 操作、正則表達式以及多線程相關(guān)的內(nèi)容禀晓。
15.1 Kotlin IO 簡介
Kotlin的IO操作都在kotlin.io包下柄粹。Kotlin的原則就是Java已經(jīng)有的,好用的就直接使用匆绣,沒有的或者不好用的驻右,就在原有類的基礎(chǔ)上進行封裝擴展,例如Kotlin 就給 File 類寫了擴展函數(shù)崎淳。這跟Groovy的擴展API 的思想是一樣的堪夭。
15.2 終端 IO
Java 超長的輸出語句 System.out.println() 居然延續(xù)到了現(xiàn)在!同樣的工作在C++里面只需要簡單的 cout<< 就可以完成拣凹。當(dāng)然森爽,如果需要的話,我們可以在工程中直接封裝 System.out.println() 為簡單的打印方法嚣镜。
在Kotlin里面很簡單爬迟,只需要使用println或者print這兩個全局函數(shù)即可,我們不再需要冗長的前綴菊匿。當(dāng)然如果我們很懷舊付呕,就是想用 System.out.println() 计福,Kotlin 依然支持直接這么使用(與 Java 無縫互操作)。
>>> System.out.println("K")
K
>>> println("K")
K
這里的 println 函數(shù)Kotlin實現(xiàn)如下
@kotlin.internal.InlineOnly
public inline fun println(message: Any?) {
System.out.println(message)
}
當(dāng)然徽职,Kotlin 也只是在 System.out.println() 的基礎(chǔ)上進行了封裝象颖。
從終端讀取數(shù)據(jù)也很簡單,最基本的方法就是全局函數(shù)readLine姆钉,它直接從終端讀取一行作為字符串说订。如果需要更進一步的處理,可以使用Kotlin提供的各種字符串處理函數(shù)來處理和轉(zhuǎn)換字符串潮瓶。
Kotlin 的封裝終端IO 的類在 stdlib/src/kotlin/io/Console.kt 源文件中陶冷。
15.3 文件 IO 操作
Kotlin為java.io.File提供了大量好用的擴展函數(shù),這些擴展函數(shù)主要在下面三個源文件中:
kotlin/io/files/FileTreeWalk.kt |
---|
kotlin/io/files/Utils.kt |
kotlin/io/FileReadWrite.kt |
同時毯辅,Kotlin 也針對InputStream埂伦、OutputStream和 Reader 等都做了簡單的擴展。它們主要在下面的兩個源文件中:
kotlin/io/IOStreams.kt |
---|
kotlin/io/ReadWrite.kt |
Koltin 的序列化直接采用的 Java 的序列化類的類型別名:
internal typealias Serializable = java.io.Serializable
下面我們來簡單介紹一下 Kotlin 文件讀寫操作悉罕。
15.3.1 讀文件
讀取文件全部內(nèi)容
我們?nèi)绻唵巫x取一個文件赤屋,可以使用readText()方法立镶,它直接返回整個文件內(nèi)容壁袄。代碼示例如下
/**
* 獲取文件全部內(nèi)容字符串
* @param filename
*/
fun getFileContent(filename: String): String {
val f = File(filename)
return f.readText(Charset.forName("UTF-8"))
}
我們直接使用 File 對象來調(diào)用 readText 函數(shù)即可獲得該文件的全部內(nèi)容,它返回一個字符串媚媒。如果指定字符編碼嗜逻,可以通過傳入?yún)?shù)Charset來指定,默認是UTF-8編碼缭召。
如果我們想要獲得文件每行的內(nèi)容栈顷,可以簡單通過split("\n")
來獲得一個每行內(nèi)容的數(shù)組。
獲取文件每行的內(nèi)容
我們也可以直接調(diào)用 Kotlin 封裝好的readLines函數(shù)嵌巷,獲得文件每行的內(nèi)容萄凤。readLines函數(shù)返回一個持有每行內(nèi)容的 List。
/**
* 獲取文件每一行內(nèi)容搪哪,存入一個 List 中
* @param filename
*/
fun getFileLines(filename: String): List<String> {
return File(filename).readLines(Charset.forName("UTF-8"))
}
直接操作字節(jié)數(shù)組
我們?nèi)绻M苯硬僮魑募淖止?jié)數(shù)組靡努,可以使用readBytes()。如果想使用傳統(tǒng)的Java方式晓折,在Kotlin 中你也可以像 Groovy 一樣自如使用惑朦。
//讀取為bytes數(shù)組
val bytes: ByteArray = f.readBytes()
println(bytes.joinToString(separator = " "))
//直接像 Java 中的那樣處理Reader或InputStream
val reader: Reader = f.reader()
val inputStream: InputStream = f.inputStream()
val bufferedReader: BufferedReader = f.bufferedReader()
}
15.3.2 寫文件
和讀文件類似,寫入文件也很簡單漓概。我們可以寫入字符串漾月,也可以寫入字節(jié)流。還可以直接使用Java的 Writer 或者 OutputStream胃珍。
覆蓋寫文件
fun writeFile(text: String, destFile: String) {
val f = File(destFile)
if (!f.exists()) {
f.createNewFile()
}
f.writeText(text, Charset.defaultCharset())
}
末尾追加寫文件
fun appendFile(text: String, destFile: String) {
val f = File(destFile)
if (!f.exists()) {
f.createNewFile()
}
f.appendText(text, Charset.defaultCharset())
}
15.4 遍歷文件樹
和Groovy一樣梁肿,Kotlin也提供了方便的功能來遍歷文件樹蜓陌。遍歷文件樹需要調(diào)用擴展方法walk()。它會返回一個FileTreeWalk對象栈雳,它有一些方法用于設(shè)置遍歷方向和深度护奈,詳情參見FileTreeWalk API 文檔說明。
提示:FileTreeWalk API 文檔鏈接 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/-file-tree-walk/
下面的例子遍歷了指定文件夾下的所有文件哥纫。
fun traverseFileTree(filename: String) {
val f = File(filename)
val fileTreeWalk = f.walk()
fileTreeWalk.iterator().forEach { println(it.absolutePath) }
}
測試代碼:
@Test fun testTraverseFileTree() {
KFileUtil.traverseFileTree(".")
}
運行上面的測試代碼霉旗,它將輸出當(dāng)前目錄下的所有子目錄及其文件。
我們還可以遍歷當(dāng)前文件下面所有子目錄文件蛀骇,存入一個 Iterator<File> 中
fun getFileIterator(filename: String): Iterator<File> {
val f = File(filename)
val fileTreeWalk = f.walk()
return fileTreeWalk.iterator()
}
我們遍歷當(dāng)前文件下面所有子目錄文件厌秒,還可以根據(jù)條件過濾,并把結(jié)果存入一個 Sequence<File> 中
fun getFileSequenceBy(filename: String, p: (File) -> Boolean): Sequence<File> {
val f = File(filename)
return f.walk().filter(p)
}
測試代碼:
@Test fun testGetFileSequenceBy() {
val fileSequence1 = KFileUtil.getFileSequenceBy(".", {
it.isDirectory
})
fileSequence1.forEach { println("fileSequence1: ${it.absoluteFile} ") }
val fileSequence2 = KFileUtil.getFileSequenceBy(".", {
it.isFile
})
fileSequence2.forEach { println("fileSequence2: ${it.absoluteFile} ") }
val fileSequence3 = KFileUtil.getFileSequenceBy(".", {
it.extension == "kt"
})
fileSequence3.forEach { println("fileSequence3: ${it.absoluteFile} ") }
}
在工程中運行上面的測試代碼擅憔,它將會有類似下面的輸出:
...
...
fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KFileUtil.kt
fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KNetUtil.kt
fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KShellUtil.kt
fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/test/kotlin/com/easy/kotlin/fileio/KFileUtilTest.kt
15.5 網(wǎng)絡(luò)IO操作
Kotlin為java.net.URL增加了兩個擴展方法鸵闪,readBytes和readText。我們可以方便的使用這兩個方法配合正則表達式實現(xiàn)網(wǎng)絡(luò)爬蟲的功能暑诸。
下面我們簡單寫幾個函數(shù)實例蚌讼。
根據(jù) url 獲取該 url 的響應(yīng) HTML函數(shù)
fun getUrlContent(url: String): String {
return URL(url).readText(Charset.defaultCharset())
}
根據(jù) url 獲取該 url 響應(yīng)比特數(shù)組函數(shù)
fun getUrlBytes(url: String): ByteArray {
return URL(url).readBytes()
}
把 url 響應(yīng)字節(jié)數(shù)組寫入文件
fun writeUrlBytesTo(filename: String, url: String) {
val bytes = URL(url).readBytes()
File(filename).writeBytes(bytes)
}
下面這個例子簡單的獲取了百度首頁的源代碼。
getUrlContent("https://www.baidu.com")
下面這個例子根據(jù) url 來獲取一張圖片的比特流个榕,然后調(diào)用readBytes()方法讀取到字節(jié)流并寫入文件篡石。
writeUrlBytesTo("圖片.jpg", "http://n.sinaimg.cn/default/4_img/uplaod/3933d981/20170622/2fIE-fyhfxph6601959.jpg")
在項目相應(yīng)文件夾下我們可以看到下載好的 “圖片.jpg” 。
15.6 kotlin.io標準庫
Kotlin 的 io 庫主要是擴展 Java 的 io 庫西采。下面我們簡單舉幾個例子凰萨。
appendBytes
追加字節(jié)數(shù)組到該文件中
方法簽名:
fun File.appendBytes(array: ByteArray)
appendText
追加文本到該文件中
方法簽名:
fun File.appendText(
text: String,
charset: Charset = Charsets.UTF_8)
bufferedReader
獲取該文件的BufferedReader
方法簽名:
fun File.bufferedReader(
charset: Charset = Charsets.UTF_8,
bufferSize: Int = DEFAULT_BUFFER_SIZE
): BufferedReader
bufferedWriter
獲取該文件的BufferedWriter
方法簽名:
fun File.bufferedWriter(
charset: Charset = Charsets.UTF_8,
bufferSize: Int = DEFAULT_BUFFER_SIZE
): BufferedWriter
copyRecursively
復(fù)制該文件或者遞歸復(fù)制該目錄及其所有子文件到指定路徑,如果指定路徑下的文件不存在械馆,會自動創(chuàng)建胖眷。
方法簽名:
fun File.copyRecursively(
target: File,
overwrite: Boolean = false, // 是否覆蓋。true:覆蓋之前先刪除原來的文件
onError: (File, IOException) -> OnErrorAction = { _, exception -> throw exception }
): Boolean
提示: Kotlin 對 File 的擴展函數(shù) API 文檔https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-file/index.html |
---|
關(guān)于 kotlin.io 下面的API文檔在這里 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/index.html |
15.7 執(zhí)行Shell命令行
我們使用 Groovy 的文件 IO 操作感覺非常好用霹崎,例如
package com.easy.kotlin
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4)
class ShellExecuteDemoTest {
@Test
def void testShellExecute() {
def p = "ls -R".execute()
def output = p.inputStream.text
println(output)
def fname = "我圖.url"
def f = new File(fname)
def lines = f.readLines()
lines.forEach({
println(it)
})
println(f.text)
}
}
Kotlin 中的文件 IO珊搀,網(wǎng)絡(luò) IO 操作跟 Groovy一樣簡單。
另外尾菇,從上面的代碼中我們看到使用 Groovy 執(zhí)行終端命令非常簡單:
def p = "ls -R".execute()
def output = p.inputStream.text
在 Kotlin 中境析,目前還沒有對 String 類和 Process 擴展這樣的函數(shù)。其實擴展這樣的函數(shù)非常簡單错沽。我們完全可以自己擴展簿晓。
首先,我們來擴展 String 的 execute() 函數(shù)千埃。
fun String.execute(): Process {
val runtime = Runtime.getRuntime()
return runtime.exec(this)
}
然后憔儿,我們來給 Process 類擴展一個 text函數(shù)。
fun Process.text(): String {
var output = ""
// 輸出 Shell 執(zhí)行的結(jié)果
val inputStream = this.inputStream
val isr = InputStreamReader(inputStream)
val reader = BufferedReader(isr)
var line: String? = ""
while (line != null) {
line = reader.readLine()
output += line + "\n"
}
return output
}
完成了上面兩個簡單的擴展函數(shù)之后放可,我們就可以在下面的測試代碼中谒臼,可以像 Groovy 一樣執(zhí)行終端命令了:
val p = "ls -al".execute()
val exitCode = p.waitFor()
val text = p.text()
println(exitCode)
println(text)
實際上朝刊,通過之前的很多實例的學(xué)習(xí),我們可以看出 Kotlin 的擴展函數(shù)相當(dāng)實用蜈缤。Kotlin 語言本身API 也大量使用了擴展功能拾氓。
15.8 正則表達式
我們在 Kotlin 中除了仍然可以使用 Java中的 Pattern,Matcher 等類之外底哥,Kotlin 還提供了一個正則表達式類 kotlin/text/regex/Regex.kt 咙鞍,我們通過 Regex 的構(gòu)造函數(shù)來創(chuàng)建一個正則表達式。
15.8.1 構(gòu)造 Regex 表達式
使用Regex構(gòu)造函數(shù)
>>> val r1 = Regex("[a-z]+")
>>> val r2 = Regex("[a-z]+", RegexOption.IGNORE_CASE)
其中的匹配選項 RegexOption 是直接使用的 Java 類 Pattern中的正則匹配選項趾徽。
使用 String 的 toRegex 擴展函數(shù)
>>> val r3 = "[A-Z]+".toRegex()
15.8.2 Regex 函數(shù)
Regex 里面提供了豐富的簡單而實用的函數(shù)续滋,如下表所示
函數(shù)名稱 | 功能說明 |
---|---|
matches(input: CharSequence): Boolean | 輸入字符串全部匹配 |
containsMatchIn(input: CharSequence): Boolean | 輸入字符串至少有一個匹配 |
matchEntire(input: CharSequence): MatchResult? | 輸入字符串全部匹配,返回一個匹配結(jié)果對象 |
replace(input: CharSequence, replacement: String): String | 把輸入字符串中匹配的部分替換成replacement的內(nèi)容 |
replace(input: CharSequence, transform: (MatchResult) -> CharSequence): String | 把輸入字符串中匹配到的值孵奶,用函數(shù) transform映射之后的新值替換 |
find(input: CharSequence, startIndex: Int = 0): MatchResult? | 返回輸入字符串中第一個匹配的值 |
findAll(input: CharSequence, startIndex: Int = 0): Sequence<MatchResult> | 返回輸入字符串中所有匹配的值MatchResult的序列 |
下面我們分別就上面的函數(shù)給出簡單實例疲酌。
matches
輸入字符串全部匹配正則表達式返回 true , 否則返回 false。
>>> val r1 = Regex("[a-z]+")
>>> r1.matches("ABCzxc")
false
>>>
>>> val r2 = Regex("[a-z]+", RegexOption.IGNORE_CASE)
>>> r2.matches("ABCzxc")
true
>>> val r3 = "[A-Z]+".toRegex()
>>> r3.matches("GGMM")
true
containsMatchIn
輸入字符串中至少有一個匹配就返回true了袁,沒有一個匹配就返回false朗恳。
>>> val re = Regex("[0-9]+")
>>> re.containsMatchIn("012Abc")
true
>>> re.containsMatchIn("Abc")
false
matchEntire
輸入字符串全部匹配正則表達式返回 一個MatcherMatchResult對象,否則返回 null载绿。
>>> val re = Regex("[0-9]+")
>>> re.matchEntire("1234567890")
kotlin.text.MatcherMatchResult@34d713a2
>>> re.matchEntire("1234567890!")
null
我們可以訪問MatcherMatchResult的value熟悉來獲得匹配的值粥诫。
>>> re.matchEntire("1234567890")?.value
1234567890
由于 matchEntire 函數(shù)的返回是MatchResult? 可空對象,所以這里我們使用了安全調(diào)用符號 ?.
卢鹦。
replace(input: CharSequence, replacement: String): String
把輸入字符串中匹配的部分替換成replacement的內(nèi)容臀脏。
>>> val re = Regex("[0-9]+")
>>> re.replace("12345XYZ","abcd")
abcdXYZ
我們可以看到劝堪,"12345XYZ"中12345
是匹配正則表達式 [0-9]+
的內(nèi)容冀自,它被替換成了 abcd
。
replace(input: CharSequence, transform: (MatchResult) -> CharSequence): String
把輸入字符串中匹配到的值秒啦,用函數(shù) transform映射之后的新值替換熬粗。
>>> val re = Regex("[0-9]+")
>>> re.replace("9XYZ8", { (it.value.toInt() * it.value.toInt()).toString() })
81XYZ64
我們可以看到,9XYZ8
中數(shù)字9和8是匹配正則表達式[0-9]+
的內(nèi)容余境,它們分別被transform函數(shù)映射 (it.value.toInt() * it.value.toInt()).toString()
的新值 81 和 64 替換驻呐。
find
返回輸入字符串中第一個匹配的MatcherMatchResult對象。
>>> val re = Regex("[0-9]+")
>>> re.find("123XYZ987abcd7777")
kotlin.text.MatcherMatchResult@4d4436d0
>>> re.find("123XYZ987abcd7777")?.value
123
findAll
返回輸入字符串中所有匹配的值的MatchResult的序列芳来。
>>> val re = Regex("[0-9]+")
>>> re.findAll("123XYZ987abcd7777")
kotlin.sequences.GeneratorSequence@f245bdd
我們可以通過 forEach 循環(huán)遍歷所以匹配的值
>>> re.findAll("123XYZ987abcd7777").forEach{println(it.value)}
123
987
7777
15.8.3 使用 Java 正則表達式類
除了上面 Kotlin 提供的函數(shù)之外含末,我們在 Kotlin 中仍然可以使用 Java 的正則表達式的 API。
val re = Regex("[0-9]+")
val p = re.toPattern()
val m = p.matcher("888ABC999")
while (m.find()) {
val d = m.group()
println(d)
}
上面的代碼運行輸出:
888
999
15.9 Kotlin 的多線程
Kotlin中沒有synchronized關(guān)鍵字即舌。
Kotlin中沒有volatile關(guān)鍵字佣盒。
Kotlin的Any類似于Java的Object,但是沒有wait()顽聂,notify()和notifyAll() 方法肥惭。
那么并發(fā)如何在Kotlin中工作呢盯仪?放心,Kotlin 既然是站在 Java 的肩膀上蜜葱,當(dāng)然少不了對多線程編程的支持——Kotlin通過封裝 Java 中的線程類全景,簡化了我們的編碼。同時我們也可以使用一些特定的注解牵囤, 直接使用 Java 中的同步關(guān)鍵字等爸黄。下面我們簡單介紹一下使用Kotlin 進行多線程編程的相關(guān)內(nèi)容。
15.9.1 創(chuàng)建線程
我們在 Java中通常有兩種方法在Java中創(chuàng)建線程:
- 擴展Thread類
- 或者實例化它并通過構(gòu)造函數(shù)傳遞一個Runnable
因為我們可以很容易地在Kotlin中使用Java類揭鳞,這兩個方式都可以使用馆纳。
使用對象表達式創(chuàng)建
object : Thread() {
override fun run() {
Thread.sleep(3000)
println("A 使用 Thread 對象表達式: ${Thread.currentThread()}")
}
}.start()
此代碼使用Kotlin的對象表達式創(chuàng)建一個匿名類并覆蓋run()方法。
使用 Lambda 表達式
下面是如何將一個Runnable傳遞給一個新創(chuàng)建的Thread實例:
Thread({
Thread.sleep(2000)
println("B 使用 Lambda 表達式: ${Thread.currentThread()}")
}).start()
我們在這里看不到Runnable汹桦,在Kotlin中可以很方便的直接使用上面的Lambda表達式來表達鲁驶。
還有更簡單的方法嗎? 且看下文解說舞骆。
使用 Kotlin 封裝的 thread 函數(shù)
例如钥弯,我們寫了下面一段線程的代碼
val t = Thread({
Thread.sleep(2000)
println("C 使用 Lambda 表達式:${Thread.currentThread()}")
})
t.isDaemon = false
t.name = "CThread"
t.priority = 3
t.start()
后面的四行可以說是樣板化的代碼。在 Kotlin 中把這樣的操作封裝簡化了督禽。
thread(start = true, isDaemon = false, name = "DThread", priority = 3) {
Thread.sleep(1000)
println("D 使用 Kotlin 封裝的函數(shù) thread(): ${Thread.currentThread()}")
}
這樣的代碼顯得更加精簡整潔了脆霎。事實上,thread()函數(shù)就是對我們編程實踐中經(jīng)常用到的樣板化的代碼進行了抽象封裝狈惫,它的實現(xiàn)如下:
public fun thread(start: Boolean = true, isDaemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority: Int = -1, block: () -> Unit): Thread {
val thread = object : Thread() {
public override fun run() {
block()
}
}
if (isDaemon)
thread.isDaemon = true
if (priority > 0)
thread.priority = priority
if (name != null)
thread.name = name
if (contextClassLoader != null)
thread.contextClassLoader = contextClassLoader
if (start)
thread.start()
return thread
}
這只是一個非常方便的包裝函數(shù)睛蛛,簡單實用。從上面的例子我們可以看出胧谈,Kotlin 通過擴展 Java 的線程 API忆肾,簡化了樣板代碼。
15.9.2 同步方法和塊
synchronized不是Kotlin中的關(guān)鍵字菱肖,它替換為@Synchronized 注解客冈。 Kotlin中的同步方法的聲明將如下所示:
@Synchronized fun appendFile(text: String, destFile: String) {
val f = File(destFile)
if (!f.exists()) {
f.createNewFile()
}
f.appendText(text, Charset.defaultCharset())
}
@Synchronized 注解與 Java中的 synchronized 具有相同的效果:它會將JVM方法標記為同步。 對于同步塊稳强,我們使用synchronized() 函數(shù)场仲,它使用鎖作為參數(shù):
fun appendFileSync(text: String, destFile: String) {
val f = File(destFile)
if (!f.exists()) {
f.createNewFile()
}
synchronized(this){
f.appendText(text, Charset.defaultCharset())
}
}
跟 Java 基本一樣。
15.9.3 可變字段
同樣的退疫,Kotlin沒有 volatile 關(guān)鍵字渠缕,但是有@Volatile注解。
@Volatile private var running = false
fun start() {
running = true
thread(start = true) {
while (running) {
println("Still running: ${Thread.currentThread()}")
}
}
}
fun stop() {
running = false
println("Stopped: ${Thread.currentThread()}")
}
@Volatile會將JVM備份字段標記為volatile褒繁。
當(dāng)然亦鳞,在 Kotlin 中我們有更好用的協(xié)程并發(fā)庫。在代碼工程實踐中,我們可以根據(jù)實際情況自由選擇蚜迅。
本章小結(jié)
Kotlin 是一門工程實踐性很強的語言舵匾,從本章介紹的文件IO、正則表達式以及多線程等內(nèi)容中谁不,我們可以領(lǐng)會到 Kotlin 的基本原則:充分使用已有的 Java 生態(tài)庫坐梯,在此基礎(chǔ)之上進行更加簡單實用的擴展,大大提升程序員們的生產(chǎn)力刹帕。從中我們也體會到了Kotlin 編程中的極簡理念——不斷地抽象吵血、封裝、擴展偷溺,使之更加簡單實用蹋辅。
本章示例代碼:https://github.com/EasyKotlin/chapter15_file_io
另外,筆者綜合了本章的內(nèi)容挫掏,使用 SpringBoot + Kotlin 寫了一個簡單的圖片爬蟲 Web 應(yīng)用侦另,感興趣的讀者可參考源碼:https://github.com/EasyKotlin/chatper15_net_io_img_crawler
在下一章,也我們的最后一章中尉共,讓我們脫離 JVM褒傅,直接使用 Kotlin Native 來開發(fā)一個直接編譯成機器碼運行的 Kotlin 應(yīng)用程序。
Kotlin 開發(fā)者社區(qū)
國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號袄友,主要分享殿托、交流 Kotlin 編程語言、Spring Boot剧蚣、Android支竹、React.js/Node.js、函數(shù)式編程鸠按、編程思想等相關(guān)主題礼搁。