Kotlin IO 实例介绍,文件拷贝和目录查询

2023-07-14 10:56:28 浏览数 (1)

1. 前言

在前面介绍了IO的基本信息以及相关的函数:Kotlin I/O 的基本介绍 (zinyan.com)。而本篇将会基于上篇的介绍结合使用场景,介绍如何进行文件的复制拷贝等操作。

让我们清晰的了解IO函数的基本使用方式。

2. 字节流-文件复制

我们如果要进行文件的复制操作可以使用API提供的FileInputStreamFileOutputStream。这两个类都属于底层流,而我们在实际开发中为了提高效率有时会选择BufferedInputStreamBufferedOutputStream带有缓冲流的IO类。因为这种缓冲读取的方法可以减少直接读取数据源的次数。

缓冲字节流可以减少I/O操作次数,提高效率。

下面实例进行介绍:

代码语言:javascript复制
//介绍文件复制的基本操作
fun main(arg: Array<String>) {
    FileInputStream("D:/Text.text").use { fis -> //将D盘的文件复制了一份
        FileOutputStream("D:/Text1.text").use { fos ->
            val bis = fis.buffered()//创建字节缓冲输入流
            val bos = fos.buffered()//创建字节缓冲输出流
            bis.copyTo(bos) //将输入流数据拷贝到输出流去
            println("复制完毕")
            bos.flush()//关闭输出流
        }
    }
}

在上面的示例中,我将本地D盘的文件进行了拷贝操作。

Test1.text文件不存在,会自动创建一个文件。如果文件已经存在,会覆盖里面的内容。

我们如果只是使用了copyTo后不进行关闭flush的话。那么数据只是缓冲在内存中。还没有复制存储到新文件中。

注意:copyTo函数将输入流复制到输出流,只有当流关闭的时候数据才会被写入到文件中。否则文件大小一直为0。

我们可以通过字节流的方式复制和存储几乎所有类型的文件。但是有些文件本身属于文本类型的。那么我们使用字符流的传输方式是要比字节流快。

(PS:网络数据传输大部分是文本和指令,通过字符流传输。视频等二进制数据通过字节流传输)

3. 字符流-文件复制

字符流就不是InputOutput了,而是Reader(读)和Writer(写)。

常见方法为:

代码语言:javascript复制
//返回字符缓冲区输入流
public fun Reader.buffered(bufferSize: Int = DEFAULT_BUFFER_SIZE): BufferedReader =
    if (this is BufferedReader) this else BufferedReader(this, bufferSize)
//返回字符缓冲区输出流
public inline fun Writer.buffered(bufferSize: Int = DEFAULT_BUFFER_SIZE): BufferedWriter =
    if (this is BufferedWriter) this else BufferedWriter(this, bufferSize)
//遍历输入流中的每一行数据,对每一行数据都进行处理
public fun Reader.forEachLine(action: (String) -> Unit): Unit = useLines { it.forEach(action) }

// 读取输入流中的数据存储到一个List集合中,每一行数据就是集合的一个item。
public fun Reader.readLines(): List<String> {
    val result = arrayListOf<String>()
    forEachLine { result.add(it) }
    return result
}
//读取输入流中的数据到字符串中,返回一个String对象。
public fun Reader.readText(): String {
    val buffer = StringWriter()
    copyTo(buffer)
    return buffer.toString()
}

实际使用中的示例如下:

代码语言:javascript复制
fun main(arg: Array<String>) {
    FileReader("D:/Text.text").use { fis ->
        FileWriter("./Text1.text").use { fos ->
            //创建字符流输入缓冲流
            val bis = fis.buffered()
            //创建字符流输出缓冲流
            val bos = fos.buffered()
            //数据复制
            val size = bis.copyTo(bos)
            println("复制完毕:复制得到的字符数量:$size")
            bos.flush()//关闭
        }
    }
}

在上面的示例中,输出得到的size大小并不是你要拷贝的文件的大小,如果是采用字节流拷贝那么返回的大小就是文件的大小,而字符流拷贝时返回的大小是这个数据的字符大小。

PS:如果字符长度过高超过Long的长度那么这个就是不准确的。

4.File 的扩展

针对File的操作,Kotlin有不少的扩展函数。让我们对文件的各种操作简化了很多。

在这里简单列一下相关的扩展函数。该扩展函数存储在kotlin.io.FilesKt.class类中。

代码语言:javascript复制
//读的一些常见函数
//字节数组的形式,返回文件的内容。(可以是视频等多媒体文件)
public fun java.io.File.readBytes(): kotlin.ByteArray 
//以字符串的形式,返回文件的内容(默认字符格式是UTF-8)(只能是文本文件)
public fun java.io.File.readText(charset: java.nio.charset.Charset): kotlin.String 
//以List集合的形式,返回文件的内容。每一行内容为List的一个Item数据。(只能是文本文件)
public fun java.io.File.readLines(charset: java.nio.charset.Charset ): kotlin.collections.List<kotlin.String> 

//写的一些常见函数
//字节数组的形式,写入文件中。(和上面的读取相对应,返回值为空)
public fun java.io.File.writeBytes(array: kotlin.ByteArray): kotlin.Unit 
//写入字符串到文件中,默认字符格式编码为utf-8(建议针对文本文件进行操作)
public fun java.io.File.writeText(text: kotlin.String, charset: java.nio.charset.Charset /): kotlin.Unit

//遍历文件中的每一行数据,针对每个数据进行处理(可以批量修改文件内关键字等)
public fun java.io.File.forEachLine(charset: java.nio.charset.Charset , action: (kotlin.String) -> kotlin.Unit): kotlin.Unit 

//进行文件的复制操作(target新文件,overwrite:true覆盖目标文件,false不覆盖目标文件(default))
public fun java.io.File.copyTo(target: java.io.File, overwrite: kotlin.Boolean, bufferSize: kotlin.Int ): java.io.File

//遍历文件目录和内容 direction是指遍历的方向(Fiile.walkBottomUp(从下到上),File.walkTopDown(从上到小))
public fun java.io.File.walk(direction: kotlin.io.FileWalkDirection ): kotlin.io.FileTreeWalk

最后,通过遍历并显示目录文件的实例让我们了解一下walk函数的使用,实例:

代码语言:javascript复制
fun main(arg: Array<String>) {
    File("D://Zinyan")
        .walk()//进行遍历目录下的文件和文件夹
        .filter { it.isFile } //添加过滤,必须是文件
         .filter { it.extension=="class" } //必须是class后缀的文件
        .forEach {
            println(it) //打印满足条件的对象
        }
}

就会输出D盘下的zinyan目录下的所有文件和文件目录。它会遍历到子目录里面去。效果如下:

PS:上面的示例都是用的绝对路径,但是路径也可以填写相对路径。

到这里,基本的IO的读写和存储以及遍历等就介绍完毕了。更深入的就需要我们在实际使用中进行扩展学习了

0 人点赞