kotlin中的文件和IO流,王者笔记,万字长文轻松彻底入门Flutter

BufferedReader需要套接在其他的Reader上使用,所以创建时需要传入一个Reader,例如传入一个FileReader,BufferedWriter也是如此。也可以通过Reader和Writer类的扩展函数buffered()返回一个创建好的BufferedReader或BufferedWriter。BufferedReader继承自Reader,所以Reader类的readLines()、forEachLine、useLines扩展函数,BufferedReader同样也可以使用。BufferedReader、BufferedWriter使用示例如下:

var fileWriter = FileWriter(file, true)
val bufferedWriter = BufferedWriter(fileWriter)
bufferedWriter.write(“新增一行\n”)
bufferedWriter.close()

//使用扩展函数buffered获取BufferedWriter,
// 然后用BufferedWriter的扩展函数appendLine添加一行
fileWriter = FileWriter(file, true)
fileWriter.buffered().apply {
appendLine(“扩展函数新增一行”)
close()
}

var fileReader = FileReader(file)
val bufferedReader = BufferedReader(fileReader)
var buffer: CharArray = CharArray(1024)
var len: Int
while (bufferedReader.read(buffer).also { len = it } != -1) {
print(String(buffer, 0, len))
}
bufferedReader.close()
println(“-------------------”)

//使用扩展函数buffered获取BufferedReader,
// 然后用BufferedReader的扩展函数forEachLine逐行获取
fileReader = FileReader(file)
fileReader.buffered().forEachLine {
println(it)
}
println(“-------------------”)

fileReader = FileReader(file)
val lines = fileReader.buffered().readLines()
for (item in lines) {
println(item)
}
println(“-------------------”)

fileReader = FileReader(file)
fileReader.buffered().useLines {
it.iterator().forEach { it1 ->
println(it1)
}
}

输出

新增一行
扩展函数新增一行

新增一行
扩展函数新增一行

新增一行
扩展函数新增一行

新增一行
扩展函数新增一行

可以看出3种扩展函数更简单易用。

下边来对比一下使用了BufferedWriter和不使用BufferedWriter的效率差别,见如下示例:

val time1 = measureTime {
val longFile = File(getExternalFilesDir(“”)?.absolutePath + “/View.java”)
val fileWriter = FileWriter(File(getExternalFilesDir(“”)?.absolutePath + “/View1.txt”), true)
val bufferedWriter = BufferedWriter(fileWriter)
longFile.forEachLine {
bufferedWriter.write(it)
}
bufferedWriter.flush()
bufferedWriter.close()
}
println(“使用BufferedWriter耗时$time1”)

val time2 = measureTime {
val longFile = File(getExternalFilesDir(“”)?.absolutePath + “/View.java”)
val fileWriter = FileWriter(File(getExternalFilesDir(“”)?.absolutePath + “/View2.txt”), true)
longFile.forEachLine {
fileWriter.write(it)
}
fileWriter.close()
}
println(“不使用的情况耗时$time2”)

输出

使用BufferedWriter耗时102ms
不使用的情况耗时351ms

示例中我将Android的View的源码的2倍作为数据源,然后分别用FileWriter和BufferedWriter将数据源复制到另外两个TXT中。这里用View的源码的2倍作为数据源是因为View的源码只有1M多,体现不出差异,所以复制了一遍。

输出可以看出,使用BufferedWriter的耗时是不使用时的1/3不到,如果文件再大一些,差异可能更明显。为什么使用缓冲后能提升效率呢,简单理解就是:使用缓冲处理流包装就是一堆一堆的干活,不用CPU多次处理数据转换,只是设置一下数据转换成功后的文件。不使用缓冲处理流包装就是CPU傻傻的一个字节一个字节循环来干活存储写入文件中,相比可见效率明显变慢。所以建议总是使用缓冲流

BufferedInputStream、BufferedOutputStream

类似于BufferedReader、BufferedWriter,可以使用InputStream/OutputStream的buffered()扩展函数获取对应的BufferedInputStream、BufferedOutputStream,贴上示例代码:

var fileOutputStream = FileOutputStream(file, true)
val bufferedOutputStream = BufferedOutputStream(fileOutputStream)
bufferedOutputStream.write(“这是一行数据\n”.toByteArray())
bufferedOutputStream.close()

fileOutputStream = FileOutputStream(file, true)
fileOutputStream.buffered().apply {
write(“扩展函数新增的数据\n”.toByteArray())
close()
}

var fileInputStream = FileInputStream(file)
val bufferedInputStream = BufferedInputStream(fileInputStream)
val buffer = ByteArray(1024)
var len: Int
while (bufferedInputStream.read(buffer).also { len = it } != -1) {
print(String(buffer, 0, len))
}
bufferedInputStream.close()
println(“-------------”)

//使用扩展方法buffered()获取BufferedInputStream,
//再调用BufferedInputStream的readBytes()扩展方法,一次获取所有的数据
fileInputStream = FileInputStream(file)
fileInputStream.buffered().apply {
print(String(readBytes()))
close()
}

对象流

DataInputStream类和 DataOutputStream 类可以实现基本数据类型与字符串的输入和输出。 而 ObjectlnputStream 类和 ObjectOutputStream 类除了可以实现基本数据类型与字符串的输入和输出之外, 还可以实现对象的输入和输出。 由于 ObjectlnputStream 类和ObjectOutputStream 类包含 DatalnputStream 类和DataOutputStream 类的所有功能, 所以, 完全可以用 ObjectlnputStream 类和 ObjectOutputStream 类代替 DatalnputStream 类和DataOutputStream 类 。

序列化

并不是每一个对象都可以写到输出流,可以写入到输出流中的对象称为可序列化的。对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。如果需要让某个对象支持序列化机制,则必须让其类是可序列化的为了让某个类是可序列化的,该类必须实现Serializable或者Externalizable。

凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:serialVersionUID,serialVersionUID用来表明类的不同版本间的兼容性。如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的源代码作了修改,serialVersionUID可能发生变化,这就会导致使用旧版类创建的流将无法恢复成新版的类对象。故建议,显示声明serialVersionUID。如果希望类的不同版本对序列化兼容,需确保类的不同版本具有相同的serialVersionUID;如果不希望类的不同版本对序列化兼容,因此需确保类的不同版本具有不同的serialVersionUID。

如果一个对象是 Serializable 的实例, 但它包含了非序列化的属性, 那么可以序列化这个对象吗? 答案是否定的。 为了使该对象是可序列化的, 需要给这些属性加上关键字transient, 告诉 Java 虚拟机将对象写入对象流时忽略这些属性。

ObjectlnputStream

ObjectlnputStream 类和 ObjectOutputStream 类可以用于读 / 写可序列化的对象 。示例如下:

val fileOutputStream = FileOutputStream(file, true)
val objectOutputStream = ObjectOutputStream(fileOutputStream)
objectOutputStream.writeObject(Book(“Android从入门到放弃”, 100, “人民邮电出版社”))
objectOutputStream.writeObject(Book(“颈椎病的治疗”, 200, “北京大学出版社”))
objectOutputStream.close()
fileOutputStream.close()

val fileInputStream = FileInputStream(file)
val objectInputStream = ObjectInputStream(fileInputStream)
try {
while (true) {
objectInputStream.readObject().also {
val book = it as Book
println(book.toString())
}
}
} catch (e: EOFException) {

} finally {
objectInputStream.close()
fileInputStream.close()
}

Book类实现了Serializable

data class Book(val name: String, var page: Int, var publisher: String) : Serializable

输出

Book(name=Android从入门到放弃, page=100, publisher=人民邮电出版社)
Book(name=颈椎病的治疗, page=200, publisher=北京大学出版社)

上述代码第一次写入没有问题,再次写入后会有问题,错误信息为:java.io.StreamCorruptedException: invalid type code: AC。解决方式参考

www.iteye.com/blog/halzha…

RandomAccessFile

上边讲的都只能追加或者覆盖,无法实现任意位置的读写,所以Java 提供了 RandomAccessFile 类, 允许从文件的任何位置进行数据的读写 。RandomAccessFile对象包含一个记录指针,用以标示当前读写处的位置。RandomAccessFile类对象可以自由移动记录指针:

  • long getFilePointer():获取文件记录指针的当前位置
  • void seek(long pos):将文件记录指针定位到pos位置

使用示例如下:

//RandomAccessFile的read和write都会改变指针位置。
val randomAccessFile = RandomAccessFile(file, “rw”)
val data1 = “这是数据1\n”
randomAccessFile.write(data1.toByteArray())
randomAccessFile.write(“这是数据2\n”.toByteArray())
randomAccessFile.close()

val randomAccessFile1 = RandomAccessFile(file, “rw”)
randomAccessFile1.seek(data1.toByteArray().size.toLong())
println(“当前指针位置1,” + randomAccessFile1.filePointer)
//取出data1之后的数据
var stringAfterData1 = “”
var buffer = ByteArray(1024)
var len: Int
while (randomAccessFile1.read(buffer).also { len = it } != -1) {
stringAfterData1 += String(buffer, 0, len)
}
println(“当前指针位置2,” + randomAccessFile1.filePointer)
randomAccessFile1.seek(data1.toByteArray().size.toLong())
randomAccessFile1.write(“这一行数据插入在数据1和2之间\n”.toByteArray())
//将插入之前data1之后的数据追加上
randomAccessFile1.write(stringAfterData1.toByteArray())
println(“当前指针位置3,” + randomAccessFile1.filePointer)
println(“当前数据长度,” + randomAccessFile1.length())
//重新移动指针到开头,取出所有数据
randomAccessFile1.seek(0)
while (randomAccessFile1.read(buffer).also { len = it } != -1) {
print(String(buffer, 0, len))
}
println(“当前指针位置4,” + randomAccessFile1.filePointer)
randomAccessFile1.close()

输出
当前指针位置1,14
当前指针位置2,28

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

腾讯T3架构师学习专题资料

如果你觉得自己学习效率低,缺乏正确的指导,可以点击加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

如果你觉得自己学习效率低,缺乏正确的指导,可以点击加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!**

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值