适用于Android开发者IO流知识

400 阅读6分钟

什么是IO

一般Android中,认为的iojava IOJava IO 也称为IO流,IO = 流,它的核心就是对文件的操作,对于 字节字符类型的输入和输出流

iostream2xx.png IO是指对数据流的输入和输出,也称为IO流IO流主要分为两大类,字节流字符流。字节流可以处理任何类型的数据,如图片,视频等,字符流只能处理字符类型的数据。

IO流的本质是数据传输,并且流是单向的。

常用的字节流FileInputStreamFileOutputStreamObjectInputStreamObjectOutputStream

IO分阻塞型IO和非阻塞型IO(NIO)

阻塞型IO在读取数据时,如果数据未到达,会一直阻塞到读取到数据为止,所以称为阻塞型IO,在高并发的环境下性能不佳。

NIO不是使用 “流” 来作为数据的传输方式,而是使用通道,通道的数据传输是双向的,且NIO的数据写入和读取都是异步的,不会阻塞线程,所以称为非阻塞型IO,在高并发的环境下性能很好。但是,NIO只是支持非阻塞式,默认还是阻塞式,只有在网络交互时支持非阻塞式,文件交互不支持。基于这些特性,基本上,在日常的Android开发中,很少见到NIO的身影

什么是流?

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在设备间传输称之为流。
本质是数据传输,根据数据传输的特性将流区分为各种类,方便更直观的进行数据操作。

  • 数据处理的不同类型分为:字节流和字符流
  • 数据流向不同分为:输入流和输出流

什么是字节流?

程序中的输入输出都是以的形式保存的(输入流or输出流),流中保存的实际上全都是字节(一个字节等于一个Byte8个bit)文件。Java提供了OutputStreamInputStream两个专门操作字节流的类。

知识补充1:
计算机能存储的唯一东西就是 bytes,为了在计算机中存储东西,我们首先得将其编码(encode),例如将其转化为 bytes
比如:要想保存音乐(以字节形式保存),我们首先得用 MP3, WAV 等将其编码;要想保存图片,我们首先得用 PNG, JPEG 等将其编码;要想保存文本,我们首先得用 ASCII, UTF-8 等将其编码.
知识补充2:
Unicode 是字符集,不是字符编码。Unicode 把全世界的字符都搜集并且编号了,但是没有规定具体的编码规则。编码规则有 UTF-8、GBK等。

字节流适合所有类型文件的数据传输,因为字节(Byte)是电脑中表示信息含义的最小单位(通常情况下一个ACSII码就是一个字节的空间来存放)。

什么是字符流?

字符流按字符(一个字符占两个字节)读数据:一次读两个字节,返回了这两个字节所对应的字符的int型数值(编码)。写入文件时把这两个字节的内容解码成这个字符在Unicode码下对应的二进制数据写入。即把原始文件中的二进制数据以字符形式读出,再将字符以二进制形式写入,所以得到的文件以字符方式存储。字符流只能处理字符或者字符串。Java提供了WriterReader两个专门操作字节流的类。

字符流只能够处理纯文本(中文)数据,其他类型数据不行,但是字符流处理文本要比字节流处理文本要方便。

字节流跟字符流的区别

1.字节流没有使用到缓冲区(内存),是与文件本身直接操作的。字符流使用到了缓冲区,在缓冲区的数据需要使用close()或者flush()方法强制刷新缓冲区将其输出(程序没有关闭数据是不会从缓冲区输出出来的)。

2.字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容。

3.在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

4.字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以处理。

5.流按字节读数据,而字节不需要编码、解码,只有字节与字符之间转换时才需要编码、解码!

字节流与字符流的转换

在jdk中,提供了两个类用于实现将字节流转化为字符流,分别为InputStreamReader和OutputStreamWriter。InputStreamReade是Reader的子类,它可以将一个字节输入流转化为字符输入流,方便直接读入字符。OutputStreamWriter是Writer的子类,它将字节输出流转化为字符输出流,方便直接写入字符。

转换流的原理是:字符流 = 字节流 + 编码表。 在转换流中选择正确的编码非常的重要,因为指定了编码,它所对应的字符集自然就指定了,否则很容易出现乱码,所以编码才是我们最终要关心的。

转换流的特点:其是字符流和字节流之间的桥梁。

  • 可对读取到的字节数据经过指定编码转换成字符

  • 可对读取到的字符数据经过指定编码转换成字节

那么何时使用转换流?

  • 当字节和字符之间有转换动作时

  • 流操作的数据需要编码或解码时

fun ioWrite() {
    try {
        FileOutputStream(filePath).use { fileOutputStream ->
           OutputStreamWriter(fileOutputStream,"GBK").use { 
               it.write("java hello")
           }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}


fun ioRead() {
    try {
        FileInputStream(filePath).use { fileInputStream ->
         InputStreamReader(fileInputStream).use {
             val charArray = CharArray(1024)
             val len = it.read(charArray)
             println(String(charArray, 0, len))
         }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

常用的IO实例

1、字节流写文件

fun ioWrite() {
    try {
        //use会自动调用close
        FileOutputStream(filePath).use { fileOutputStream ->
            fileOutputStream.write('h.toInt())
            fileOutputStream.write('a'.toInt())
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

2、字节流读文件

fun ioRead() {
    try {
        FileInputStream(filePath).use { fileInputStream ->
            println(fileInputStream.read().toChar())
            println(fileInputStream.read().toChar())
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

3、字节流加入buffer写文件

fun ioBufferWrite() {
    try {
        FileOutputStream(filePath).use { fileOutputStream ->
            BufferedOutputStream(fileOutputStream).use {
                it.write('c'.code)
                it.write('b'.code)
                it.flush()
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

4、字节流加入buffer读文件

fun ioBufferRead() {
    try {
        FileInputStream(filePath).use { fileInputStream ->
            BufferedInputStream(fileInputStream).use {
                println(it.read().toChar())
                println(it.read().toChar())
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

5、字符流写文件

fun ioWriter() {
    try {
        FileWriter(filePath).use {
            val str = "hello haha"
            it.write(str)
        }
    } catch (e: IOException) {

    }
}

6、字符流读文件

fun ioReader() {

    try {
        FileReader(filePath).use {
            val charArray = CharArray(1024)
            val len = it.read(charArray)
            println(String(charArray, 0, len))

        }
    } catch (e: IOException) {

    }
}

7、复制文件

fun ioCopyFile() {
    try {
        BufferedInputStream(FileInputStream(filePath)).use { inputStream ->
            BufferedOutputStream(FileOutputStream(copyFilePath))
                .use { outputStream ->
                    val data = ByteArray(1024)
                    var read: Int
                    while (inputStream.read(data).also { read = it } != -1) {
                        outputStream.write(data, 0, read)
                    }
                }
        }

    } catch (e: FileNotFoundException) {

    } catch (e: IOException) {

    }
}

致谢