java常用的字节流和字符流操作

1,345 阅读5分钟

@[toc]

在这里插入图片描述

前言

java 的 IO 流有很多类,常见常用的也就是字节流 InputStream 和 OutputStream 输入输出流,这是字节流两个顶级父类(当然上面还有接口),还有 FileReader 和 FileWriter 输入输出流,这是字符流两个顶级父类

输入和输出可以理解为相对于内存或者屏幕来说的,从磁盘读取到内存中是输入,写进磁盘则表示输出。所以很好理解, InputStream 和 FileReader 用来做读取数据操作,OutputStream 和 FileWriter 用来做把数据写入磁盘的操作

下面这有一张菜鸟教程中的图片,很清晰的展示了各个类之间的父子关系

img

字节流

常用的 OutputStream 和 InputStream 是输出流和输入流,二者都是抽象类,然后我们常用其中的 FileOutStream 和 FileInputStream,还有一个缓冲流 BufferedOutputStream 和 BufferedInputStream 是一个缓冲器,构造器分别接收 OutputStream 和 InputStream 的参数类型

字节流的追加就是在构造器的时候第二个参数传入 true 即可,不传默认是 false 就是完全覆盖

OutputStream 字节输出流

字节输出流,下图中我们知道 java.io 包中有如下这些字节输出流的类,其中 OutputStream 是一个抽象类

其实绝大部分程序员最常用的也就是 FileOutputStream 和 BufferedOutputStream

在这里插入图片描述

小例子如下,其写入文件磁盘只能接收 int 和 byte 类型,int 就是 ascall 码对应的数字,字节就是一个字节,注意可不是 char 类型

如果我们不是用 buffer 也行,如果使用的话buffer.close()必加,不加的话 buffer 中的字节没办法存进磁盘中!!!

public class IOOperation {
    @Test
    public void fun() throws IOException {
        FileOutputStream stream = new FileOutputStream("src\\test\\java\\temp.txt");
        BufferedOutputStream buffer = new BufferedOutputStream(stream);
        buffer.write(new byte[]{'a', 'b', 'c'});
        buffer.close();
        stream.close();
    }
}

注意点

  • 如果使用了 buffer 注意要加``buffer.close()`否则不会将缓冲区的内容写进磁盘!

InputStream 字节输入流

字节输入流,下图中我们知道 java.io 包中有如下这些字节输出流的类,其中 InputStream 是一个抽象类

其实绝大部分程序员最常用的也就是 FileInputStream 和 BufferedInputStream

在这里插入图片描述

public class IOOperation {
    @Test
    public void fun() throws IOException {
        FileInputStream stream = new FileInputStream("src\\test\\java\\temp.txt");
        BufferedInputStream buffer = new BufferedInputStream(stream);
        System.out.println(buffer.read());
        System.out.println(buffer.read());
        System.out.println(buffer.read());
        System.out.println(buffer.read());
        buffer.close();
        stream.close();
    }
}

注意点

  • 如果使用了 buffer 加不加``buffer.close()`都可以直接看到控制台有正常输出,这一点与输出流是不同的
  • 使用 read 方法如果读到没有字节了,会直接返回 -1,read 方法返回 int 类型
  • 每次使用 read 方法之后,一个字节一个字节的往后读

字符流

Writer 和 Reader 分别是字符输出流和字符输入流,二者都是抽象类,然后往下继承的子类 OutputStreamWriter 和 InputStreamReader 都是实体类

字符流的追加就是在构造器的时候第二个参数传入 true 即可,不传默认是 false 就是完全覆盖

Writer 字符输出流

字符输出流

其实一般情况下我们使用最多也就是 FileWriter 和 BufferedWriter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L998TSOZ-1593351677418)(C:\Users\石磊\Desktop\霍格沃茨培训\学习笔记\框架优化\FileWriter.png)]

下面有个小例子,展示的是追加文件,先进入下一行,然后写上 aaabbbccc

public class IOOperation {
    @Test
    public void fun() throws IOException {
        FileWriter writer = new FileWriter("src\\test\\java\\temp.txt", true);
        BufferedWriter buffer = new BufferedWriter(writer);
        buffer.newLine();
        buffer.write("aaa");
        buffer.append("bbb").append("ccc");
        buffer.close();
        writer.close();
    }
}

注意点

  • 字符流除了有 write 方法,还有 append 方法,write 方法没有返回值且不可接受 null,但是 append 方法似乎就要灵活一些了,可以接收 null,写入磁盘就是 null 的字符串,而且有返回值,返回就是字符流本身,因此可以不断的.append("").append("")的形式
  • buffer 必加上 close,否则磁盘没有内容

Reader 字符输入流

字符输入流

其实一般情况下我们使用最多也就是 FIleReader 和 BufferedReader

在这里插入图片描述

我们直接看下面的例子即可

public class IOOperation {
    @Test
    public void fun() throws IOException {
        FileReader reader = new FileReader("src\\test\\java\\temp.txt");
        BufferedReader buffer = new BufferedReader(reader);
        System.out.println(buffer.read());
        System.out.println(buffer.readLine());
        buffer.close();
        reader.close();
    }
}

注意点

  • 与字节流相似,输入字符流在使用 buffer 时候没有加 close 关掉 buffer 也一样是可以把文件中的内容读取到控制台中的,相比输出字符流就必须要加上 buffer 的 close 方法了
  • read 方法返回 int 型,也就是一个字符的 ascall 码,readLine 方法可以返回当前位置后一整行的字符串类型
  • 如果 read 方法读不到字符了它会返回 -1,如果 readLine 方法读不到行了它会返回 null 的字符串

二者区别

字节流读取字节,字符流读取一个字符

字符流是可以设置编码方式的

字符流更加灵活,推荐文本文件使用

使用场景

如果是操作文本文件,我建议直接使用字符流来操作,简单便捷,若是图片或者其他文件(电脑中的文件都是二进制形式文件,都可以使用字节流操作),我就推荐直接使用字节流来操作了

其他注意点

  • Write 输出流的 flush() 操作是指,一般 IO 操作在有缓冲区的情况下,调用 close() 方法缓冲区才会被输出到磁盘中,如果直接执行 flush 可以在缓冲区没有满的时候手动输出一次到磁盘

  • 字节流设置编码方式可以通过 InputStreamReader 或者 OutputStreamWriter 的构造器来做,第二个参数传输编码名字,这两个类父类分别是 Reader 和 Writer,子类分别是 FileReader 和 FIleWriter,它虽然是属于字符流家族的,但实际上是做字节流的编码方式设定,InputStreamReader 构造器的第一个参数类型是 InputStream 类型,InputStream 是字节流家族的,并且我查看了源码发现如果不传第二个参数编码方式,它会执行这段代码Charset.defaultCharset().name(),它读的是配置的语言编码,或者说自己环境的语言编码

  • 如果是中文,java 字节流也是可以读取的但是读取的东西可能就不好认识了,比如说一个“啊”读取到屏幕上显示 229 149 138