Kotlin入门(27)文件读写操作
java的文件处理用到了io库java.io,该库虽然功能强大,但是与文件内容的交互还得通过输入输出流中转,致使文件读写操作颇为繁琐。因此,开发者通常得自己重新封装一个文件存取的工具类,以便在日常开发中调用。下面是一个文件工具类的简单java代码:
public class fileutil {
//保存文本文件
public static void savetext(string path, string txt) {
try {
fileoutputstream fos = new fileoutputstream(path);
fos.write(txt.getbytes());
fos.close();
} catch (exception e) {
e.printstacktrace();
}
}
//读取文本文件
public static string opentext(string path) {
string readstr = "";
try {
fileinputstream fis = new fileinputstream(path);
byte[] b = new byte[fis.available()];
fis.read(b);
readstr = new string(b);
fis.close();
} catch (exception e) {
e.printstacktrace();
}
return readstr;
}
}
从上述代码看到,仅仅是文本文件的内容保存和读取,就得规规矩矩写这么多行代码,并且还不太容易理解,对于新手来说着实不够友好。哪里有痛点,哪里就有优化,所以kotlin在文件api这块也下了一番功夫,它以java的io库为基础,利用扩展函数,添加了一些常用的文件内容读写方法,并且往往是一行代码便搞定功能,绝不拖泥带水。
比如把一段文本写入文本文件,只消调用file对象的writetext方法,即可实现写入文本的功能。真的只要一行代码,就像下面这样:
//把文本写入文件
file(file_path).writetext(content)
如此简洁又好用的代码,想必是许多开发者梦寐以求的。当然了,kotlin同样支持其它格式的数据写入,前面的writetext方法是覆盖写入文本,如果要往源文件追加文本,则可调用appendtext方法。另外像图片等二进制格式的文件,可通过字节数组的形式写入文件,kotlin提供了writebytes方法用于覆盖写入字节数组,也提供了appendbytes方法用于追加字节数组。不过由于图像存储比较特殊,牵涉到压缩格式与压缩质量,因此还得通过输出流来处理(这是bitmap的compress方法要求的),具体的图片文件写入代码如下所示:
fun saveimage(path: string, bitmap: bitmap) {
try {
val file = file(path)
//outputstream获取文件的输出流对象
//writer获取文件的writer对象
//printwriter获取文件的printwriter对象
val fos: outputstream = file.outputstream()
//压缩格式为jpeg图像,压缩质量为80%
bitmap.compress(bitmap.compressformat.jpeg, 80, fos)
fos.flush()
fos.close()
} catch (e: exception) {
e.printstacktrace()
}
}
看过了文件的写入操作,再来看看文件的读取操作。有了writetext方法带好头,kotlin又提供了以下几个好看且好用的文件内容读取方法:
readtext : 读取文本形式的文件内容。
readlines : 按行读取文件内容。返回一个字符串的list,文件有多少行,队列中就有多少个元素。
readbytes : 读取字节数组形式的文件内容。
这几个方法理解起来毫不费力,从文件中读取全部的文本,也只要下面一行代码便成:
//读取文件的文本内容
val content = file(file_path).readtext()
若想从图片文件中读取位图信息,按上面的函数说明,应能调用readbytes方法。该办法确实可行,因为android的位图工厂bitmapfactory刚好提供了decodebytearray函数,用于从字节数组中解析位图,具体代码如下所示:
//方式一:利用字节数组读取位图
//readbytes读取字节数组形式的文件内容
val bytes = file(file_path).readbytes()
//decodebytearray从字节数组解析图片
val bitmap = bitmapfactory.decodebytearray(bytes, 0, bytes.size)
之前提到将位图保存为图片文件时,通过输出流进行处理;那么反过来,从图片文件读取位图数据,也可通过输入流来完成。当然多亏了bitmapfactory的decodestream方法,使得输入流解析位图能够变成现实,以下便是输入流方式读取图片的代码例子:
//方式二:利用输入流读取位图
//inputstream获取文件的输入流对象
val fis = file(file_path).inputstream()
//decodestream从输入流解析图片
val bitmap = bitmapfactory.decodestream(fis)
fis.close()
前两种读取图片文件的方式,其实都包含两个步骤:先从file对象获得文件内容,再利用位图工厂解码成位图。尽管这么做也只需两行代码,还是不如读取文本的一行代码来得精炼,对于精益求精的开发者来说,此处仍然有着改善的空间。幸好位图工厂留了一手终极大招,名叫decodefile,只要给出图片文件的完整路径,文件读取和位图解析的操作都一齐搞定了,具体代码见下:
//方式三:直接从文件路径获取位图
//decodefile从指定路径解析图片
val bitmap = bitmapfactory.decodefile(file_path)
真是想不到,光光从图片读取位图数据这个小功能,就有至少三种方式,不但学到了kotlin的文件读取api,而且温习了android的bitmapfactory类。开发者的口味各不相同,不管个人的偏好写法是啥,以上三种方式总有一款适合你。
写文件和读文件是处理单个文件,没有太复杂的需求。倘若要求遍历某个目录下面的所有文本文件或者图片文件,那可麻烦了,因为该功能的需求点可丰富了,例如要不要到子目录和孙子目录下搜索、文件跟文件夹都要匹配还是只匹配其中之一、筛选条件的文件扩展名都有哪些?想想这些详细的功能点都觉得头大,就算好不容易把符合条件的文件都挑出来,末了还得再来一个for循环完成处理操作。如果遍历功能采用java编码,新手绝对无法自己写出实现代码,饶是高手也要颇费一番折腾。
现在有了kotlin就方便多了,因为kotlin把目录遍历这个功能重新梳理了一下,归纳为filetreewalk文件树,通过给文件树设置各式各样的参数与条件,即可化繁为简,轻轻松松获取文件的搜索结果。文件树的使用很简单,首先调用file对象的walk方法得到filetreewalk实例,接着依次为该实例设置具体的条件,包括遍历深度、是否匹配文件夹、文件扩展名,以及最后的文件队列循环处理。心动不如行动,快来看看kotlin的文件遍历是怎么实现的,下面是搜寻指定目录下面所有文本文件的示例代码:
var filenames: mutablelist<string> = mutablelistof()
//在该目录下走一圈,得到文件目录树结构
val filetree: filetreewalk = file(mpath).walk()
filetree.maxdepth(1) //需遍历的目录层级为1,即无需检查子目录
.filter { it.isfile } //只挑选文件,不处理文件夹
.filter { it.extension == "txt" } //选择扩展名为txt的文本文件
.foreach { filenames.add(it.name) } //循环处理符合条件的文件
注意到以上代码判断文件扩展名使用了“it.extension == "txt"”,如果符合条件的扩展名只有一种那还好办,如果符合条件的扩展名有多个又该如何是好?譬如图片文件的扩展名既可能是png,也可能是jpg,此时若用传统的或语句判断固然可行,但并不雅观,更好的办法是利用kotlin的in条件,即判断文件的扩展名是否位于扩展名队列中,形如“it.extension in listof("png","jpg")”这样,完整的图片文件搜索代码如下所示:
var filenames: mutablelist<string> = mutablelistof()
//在该目录下走一圈,得到文件目录树结构
val filetree: filetreewalk = file(mpath).walk()
filetree.maxdepth(1) //需遍历的目录层级为1,即无需检查子目录
.filter { it.isfile } //只挑选文件,不处理文件夹
.filter { it.extension in listof("png","jpg") } //选择扩展名为png和jpg的图片文件
.foreach { filenames.add(it.name) } //循环处理符合条件的文件
见识了kotlin强大的文件操作api,真教人耳目一新,如果你厌倦了java的繁文缛节,不妨来kotlin这里小试身手。