杂记六:Java IO之字节流、字符流、缓冲流

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

1、流的特点

  • 先进先出:最先写入输出流的数据最先被输入流读取到。
  • 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
  • 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。

2、字节流、字符流和缓冲流的区别

字节流:字节流操作的单元是数据单元是8位的字节。字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。

字符流:字符流操作的是数据单元为16位的字符。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。

Java中字符是采用Unicode标准,Unicode编码中,一个英文为一个字节,一个中文为两个字节。而在UTF-8编码中,一个中文字符是3个字节。如果使用字节流处理中文,一次读写一个字符对应的字节数就不会有问题,一旦将一个字符对应的字节分裂开来,就会出现乱码了。为了更方便地处理中文这些字符,Java才推出了字符流。

缓冲流:我们知道,程序与磁盘的交互相对于内存运算是很慢的,容易成为程序的性能瓶颈。减少程序与磁盘的交互,是提升程序效率一种有效手段。缓冲流,就应用这种思路:普通流每次读写一个字节,而缓冲流在内存中设置一个缓存区,缓冲区先存储足够的待操作数据后,再与内存或磁盘进行交互。这样,在总数据量不变的情况下,通过提高每次交互的数据量,减少了交互次数。

3、常用的流相关类

3.1 字节流:FileInputStream、FileOutputStream

效率较低,不建议使用

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        OutputStream os = new FileOutputStream(file, true);
        // 要写入的字符串
        String string = "恸哭六军俱缟素,冲冠一怒为红颜。";
        // 写入文件
        os.write(string.getBytes());
        // 关闭流
        os.close();
    }

    public static String read(File file) throws IOException {
        InputStream in = new FileInputStream(file);
        // 一次性取多少个字节
        byte[] bytes = new byte[1024];
        // 用来接收读取的字节数组
        StringBuilder sb = new StringBuilder();
        // 读取到的字节数组长度,为-1时表示没有数据
        int length = 0;
        // 循环取数据
        while ((length = in.read(bytes)) != -1) {
            // 将读取的内容转换成字符串
            sb.append(new String(bytes, 0, length));
        }
        // 关闭流
        in.close();
        return sb.toString();
    }
}

3.2 缓冲字节流:BufferedInputStream、BufferedOutputStream

缓冲字节流是为高效率而设计的,真正的读写操作还是靠FileOutputStream和FileInputStream,所以其构造方法入参是这两个类的对象也就不奇怪了。

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // 缓冲字节流,提高了效率
        BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(file, true));
        // 要写入的字符串
        String string = "恸哭六军俱缟素,冲冠一怒为红颜。";
        // 写入文件
        bis.write(string.getBytes());
        // 关闭流
        bis.close();
    }

    public static String read(File file) throws IOException {
        BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));
        // 一次性取多少个字节
        byte[] bytes = new byte[1024];
        // 用来接收读取的字节数组
        StringBuilder sb = new StringBuilder();
        // 读取到的字节数组长度,为-1时表示没有数据
        int length = 0;
        // 循环取数据
        while ((length = fis.read(bytes)) != -1) {
            // 将读取的内容转换成字符串
            sb.append(new String(bytes, 0, length));
        }
        // 关闭流
        fis.close();
        return sb.toString();
    }
}

3.3 字符流:InputStreamReader、OutputStreamWriter

字符流适用于文本文件的读写,OutputStreamWriter类其实也是借助FileOutputStream类实现的,故其构造方法是FileOutputStream的对象

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // OutputStreamWriter可以显示指定字符集,否则使用默认字符集
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8");
        // 要写入的字符串
        String string = "恸哭六军俱缟素,冲冠一怒为红颜。";
        osw.write(string);
        osw.flush();
        osw.close();
    }

    public static String read(File file) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
        // 字符数组:一次读取多少个字符
        char[] chars = new char[1024];
        // 每次读取的字符数组先append到StringBuilder中
        StringBuilder sb = new StringBuilder();
        // 读取到的字符数组长度,为-1时表示没有数据
        int length;
        // 循环取数据
        while ((length = isr.read(chars)) != -1) {
            // 将读取的内容转换成字符串
            sb.append(chars, 0, length);
        }
        // 关闭流
        isr.close();
        return sb.toString();
    }
}

3.4 便携字符流:FileWriter、FileReader

Java提供了FileWriter和FileReader简化字符流的读写,new FileWriter等同于new
OutputStreamWriter(new FileOutputStream(file, true))

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        FileWriter fw = new FileWriter(file, true);
        // 要写入的字符串
        String string = "恸哭六军俱缟素,冲冠一怒为红颜。";
        fw.write(string);
        fw.flush();
        fw.close();
    }

    public static String read(File file) throws IOException {
        FileReader fr = new FileReader(file);
        // 一次性取多少个字节
        char[] chars = new char[1024];
        // 用来接收读取的字节数组
        StringBuilder sb = new StringBuilder();
        // 读取到的字节数组长度,为-1时表示没有数据
        int length;
        // 循环取数据
        while ((length = fr.read(chars)) != -1) {
            // 将读取的内容转换成字符串
            sb.append(chars, 0, length);
        }
        // 关闭流
        fr.close();
        return sb.toString();
    }
}

3.5 缓冲字符流:BufferedReader、BufferedWriter

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(new
        // FileOutputStream(file, true), "UTF-8"));
        // FileWriter可以大幅度简化代码
        BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));
        // 要写入的字符串
        String string = "恸哭六军俱缟素,冲冠一怒为红颜。";
        bw.flush();
        bw.write(string);
        bw.close();
    }

    public static String read(File file) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(file));
        // 用来接收读取的字节数组
        StringBuilder sb = new StringBuilder();
        // 按行读数据
        String line;
        // 循环取数据
        while ((line = br.readLine()) != null) {
            // 将读取的内容转换成字符串
            sb.append(line);
        }
        // 关闭流
        br.close();
        return sb.toString();
    }
}

关于flush

flush是将缓冲区的数据强制写入,其实在close的时候,也会进行一次flush的,因此close之前其实可以不用专门做flush的。但是在某些情况下,流比较大,在写的过程中,可以进行阶段性的flush。flush只在输出流中使用。

字符流自带缓冲区,在使用字符流进行输出,又没有close关闭流时,若想先输出前面的内容或者释放缓冲区,就得使用flush将缓冲区内容写到文件中。

字节流没有缓冲区,所以不需要flush。但BufferedOutputStream是个特例,它是带缓冲区的字节流,它的缓冲区每8192个字节就会将内容输出一次。如果缓冲区内容不到8192个字节,又想输出的时候,就得使用flush方法。

关于缓冲字符流

因为字符流自带缓冲区,所以缓冲字符流对于普通字符流的性能提升并不明显。我们使用缓冲字符流主要是想使用它的**readLine()、newLine()**方法。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值