bufferedReader() 在 Kotlin 中究竟是如何工作的?

Posted

技术标签:

【中文标题】bufferedReader() 在 Kotlin 中究竟是如何工作的?【英文标题】:How exactly does bufferedReader() work in Kotlin? 【发布时间】:2019-08-25 21:59:05 【问题描述】:

所以我正在尝试从我的 android 项目中的 .json 文件中读取数据:

val file = context.assets.open("myfile.json").bufferedReader().readText()

这工作正常并成功将我的.json 文件打印为一个String

但是我想知道bufferedReader()到底是什么以及为什么不能在打开的.json文件上直接调用.readText()

PS:readText() 返回一个String。然而:

val json2: JSONObject = JSONObject("mystring") 返回:

Caused by: org.json.JSONException: Value mystring of type java.lang.String cannot be converted to JSONObject

这有什么意义?

【问题讨论】:

【参考方案1】:

readText 函数被定义为Reader 的扩展:

public fun Reader.readText(): String 
    val buffer = StringWriter()
    copyTo(buffer)
    return buffer.toString()

InputStream 不是Reader,所以你必须把它转换成Reader

public inline fun InputStream.reader(charset: Charset = Charsets.UTF_8): InputStreamReader = 
    InputStreamReader(this, charset)

您可以将阅读器用作带有替代bufferedReader 功能的缓冲阅读器:

public inline fun InputStream.bufferedReader(charset: Charset = Charsets.UTF_8): BufferedReader = 
    reader(charset).buffered()

ReaderBufferedReader 是 Java 标准库的一部分,缓冲版本的描述如下:

从字符输入流中读取文本,缓冲字符以便 提供字符、数组和行的高效读取。

通常,由 Reader 发出的每个读取请求都会导致对底层字符或字节流发出相应的读取请求。它是 因此建议将 BufferedReader 包裹在任何 Read() 的 Reader 周围 操作可能成本很高,例如 FileReaders 和 InputStreamReaders...

它基本上包装了 Reader 并添加了对读取单行等的支持。

【讨论】:

【参考方案2】:
val file = context.assets.open("myfile.json").bufferedReader().readText()

这里是和上面一行做同样事情的代码。

val inputStream = context.assets.open("myfile.json")
val reader = inputStream.bufferedReader()
val file = reader.readText()

假设这里是myfile.json的内容


    "os": "Android",
    "version": "KitKat",
    "codeName": 4.4

让我们一步一步来

第一步:第一行

val inputStream = context.assets.open("myfile.json")

这将返回一个InputStream 对象,该对象从 json 文件中读取一个字节或多个字节。如果将json文件内容以字节格式打印在屏幕上,我们(作为程序员)真的很难看懂。

第二步:第二行

val reader = inputStream.bufferedReader()

这将创建一个BufferedReader对象,它从json文件中读取一个或多个字符,但是他们还有另一个有用的方法叫做readLine(),这个方法读取一行文本。行被视为由换行符 ('\n')、回车符 ('\r') 或回车符后紧跟换行符中的任何一种来终止。

让我们修改当前代码。

val inputStream = context.assets.open("myfile.json")
val reader = inputStream.bufferedReader()

// Read line by line from reader until reach the end.
var line = reader.readLine()
while(line != null) 
    Log.i("TAG", line)
    line = reader.readLine()

输出:

I/TAG: 
I/TAG:     "os": "Android",
I/TAG:     "version": "KitKat",
I/TAG:     "codeName": 4.4
I/TAG: 

正如我们所见,它们从 json 文件中打印了 5 行。但在某些情况下,我们希望将所有 json 文件打印为字符串,这就是我们进行下一步的原因。

第三步:第三行

val file = reader.readText()

这会将缓冲区读取器完全作为字符串读取。你可以自己写来做同样的事情。

val inputStream = context.assets.open("myfile.json")
val reader = inputStream.bufferedReader()

val sb = StringBuffer()

var line = reader.readLine()
while(line != null) 
    Log.i("TAG", line)
    sb.append(line).append("\n")
    line = reader.readLine()


val file = sb.toString()

Log.i("TAG", file)

输出:

I/TAG: 
        "os": "Android",
        "version": "KitKat",
        "codeName": 4.4

这个输出和reader.readText()一样。

结论: BufferReader 在其中封装了一个 InputStream(或 InputStream 的子类),然后在 InputStream 中提供逐字符而不是逐字节读取的方法。另外,他们提供readLine()方法,缓冲数据。

InputStream(逐字节)-> Reader(逐字符)

InputStream (逐字节) -> BufferReader (逐字符, 读取行,缓冲数据)。

【讨论】:

以上是关于bufferedReader() 在 Kotlin 中究竟是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

扫描仪与 BufferedReader

BufferedReader和BufferedWriter简介

BufferedReader BufferedWriter

BufferedReader 和 BufferedInputStream 的区别

在 Python 中将字节转换为 BufferedReader 对象?

BufferedReader可以在Java中自动关闭吗