在Kotlin中bufferedReader()到底如何工作?

Zor*_*gan 5 android json kotlin

所以我试图从.json我的Android项目中的文件中读取数据:

val file = context.assets.open("myfile.json").bufferedReader().readText()
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,并成功将我的.json文件作为一个文件输出String

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

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
Run Code Online (Sandbox Code Playgroud)

这有什么意义?

s1m*_*nw1 5

readText函数定义为的扩展Reader

public fun Reader.readText(): String {
    val buffer = StringWriter()
    copyTo(buffer)
    return buffer.toString()
}
Run Code Online (Sandbox Code Playgroud)

an InputStream不是Reader,因此您必须将其转换为Reader

public inline fun InputStream.reader(charset: Charset = Charsets.UTF_8): InputStreamReader = 
    InputStreamReader(this, charset)
Run Code Online (Sandbox Code Playgroud)

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

public inline fun InputStream.bufferedReader(charset: Charset = Charsets.UTF_8): BufferedReader = 
    reader(charset).buffered()
Run Code Online (Sandbox Code Playgroud)

Reader也是BufferedReaderJava标准库的一部分,缓冲版本的描述如下:

从字符输入流中读取文本,缓冲字符,以便有效读取字符,数组和行。

通常,由读取器发出的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。因此建议将BufferedReader包装在其read()操作可能会很昂贵的任何Reader周围,例如FileReaders和InputStreamReaders。

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


Nhấ*_*ang 5

val file = context.assets.open("myfile.json").bufferedReader().readText()
Run Code Online (Sandbox Code Playgroud)

这是与上一行执行相同操作的代码。

val inputStream = context.assets.open("myfile.json")
val reader = inputStream.bufferedReader()
val file = reader.readText()
Run Code Online (Sandbox Code Playgroud)

假设这里是内容 myfile.json

{
    "os": "Android",
    "version": "KitKat",
    "codeName": 4.4
}
Run Code Online (Sandbox Code Playgroud)

让我们一步一步来

第一步:第一行

val inputStream = context.assets.open("myfile.json")
Run Code Online (Sandbox Code Playgroud)

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

第 2 步:第二行

val reader = inputStream.bufferedReader()
Run Code Online (Sandbox Code Playgroud)

这将创建一个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()
}
Run Code Online (Sandbox Code Playgroud)

输出:

I/TAG: {
I/TAG:     "os": "Android",
I/TAG:     "version": "KitKat",
I/TAG:     "codeName": 4.4
I/TAG: }
Run Code Online (Sandbox Code Playgroud)

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

第三步:第三行

val file = reader.readText()
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

输出:

I/TAG: {
        "os": "Android",
        "version": "KitKat",
        "codeName": 4.4
}
Run Code Online (Sandbox Code Playgroud)

此输出与reader.readText().

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

InputStream (byte-by-byte) -> Reader (character-by-character)

InputStream (byte-by-byte) -> BufferReader (character-by-character, read line, buffer data).