Java IO流小记

目录

字节流

FileInputStream

FileOutputStream

FileInputStream&FileOutputStream

BufferedOutputStream&BufferedInputStream

PrintStream

字符流

FileReader&FileWriter&BufferedReader&BufferedWriter&

PrintWriter

字节流和字符流之间的转换


IO流按流向:输入流(读取数据),输出流(写出数据)

按数据类型:字节流,字符流

    综上,有以下几大类: 

    字节输入流(读取数据)--- InputStream

    字节输出流(写出数据)--- OutputStream

    字符输入流(读取数据)--- Reader

    字符输出流(写出数据)--- Writer

字节流

    InputStream和OutputStream为字节流的抽象类,其进行文件操作的实现类分别为FileInputStream和FileOutputStream。

    以下代码展示了它们的基本使用:

FileInputStream

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class fisDemo {
    private File file = new File("E:/data/javaIO/a.txt");

    // 单个字节的读
    @Test
    public void fis1() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            int by = 0;
            while ((by = fis.read()) != -1) {
                System.out.print((char) by);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 定义数组读
    @Test
    public void fis2() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fis.read(bytes)) != -1) {
                System.out.print(new String(bytes, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileOutputStream

import org.junit.Test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class fosDemo{
    private File file = new File("E:/data/javaIO/a.txt");
    @Test
    public void fos() {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            fos.write("a test".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileInputStream&FileOutputStream

import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class CopyFileDemo {
    private static File infile = new File("E:/data/javaIO/a.txt");
    private static File outfile = new File("E:/data/javaIO/b.txt");

    // 单个字节的读写
    @Test
    public void cf1() throws Exception {
        FileInputStream fis = new FileInputStream(infile);
        FileOutputStream fos = new FileOutputStream(outfile);
        int by = 0;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        fos.close();
        fis.close();
    }

    // 指定数组长度读写
    @Test
    public void cf2() throws Exception {
        FileInputStream fis = new FileInputStream(infile);
        FileOutputStream fos = new FileOutputStream(outfile);
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
        fos.close();
        fis.close();
    }
}

    到这里,不难发现,指定数组长度去读取和写入,效率比单个字节要高很多(废话,毕竟一次读多个字节要少循环上千倍啊!),java在设计时,也考虑到了这个问题,就专门提供了带缓冲区的字节类。这种类被称为缓冲区类。

BufferedOutputStream&BufferedInputStream

在使用以上类时,传入的是一个OutputStream或InputStream对象,而不是文件或文件路径,那是因为字节缓冲区流仅仅提供缓冲区,为高效而设计,但真正的读写操作还得依靠基本的流对象实现。

话不多说,把它们放一起比较比较下效率,(方法上面的注释就是我的实际运行结果)

import org.junit.Before;
import org.junit.Test;

import java.io.*;

public class EfficiencyCompare{
    private File inFile = new File("E:/data/javaIO/a.avi");
    private File outFile = new File("E:/data/javaIO/b.avi");

    @Before
    public void init() throws IOException {
        if (!outFile.exists()) {
            boolean res = outFile.createNewFile();
            System.out.println(res);
        }
    }

    // 共耗时115616毫秒
    @Test
    public void NoBufferedByte() throws IOException {
        long start = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream(inFile);
        FileOutputStream fos = new FileOutputStream(outFile);
        int by = 0;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        fos.close();
        fis.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒");
    }

    // 共耗时237毫秒
    @Test
    public void NoBufferedBytes() throws IOException {
        long start = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream(inFile);
        FileOutputStream fos = new FileOutputStream(outFile);
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
        fos.close();
        fis.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒");
    }

    // 共耗时1168毫秒
    @Test
    public void BufferedByte() throws IOException {
        long start = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
        int by = 0;
        while ((by = bis.read()) != -1) {
            bos.write(by);
        }
        bos.close();
        bis.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒");
    }

    // 共耗时137毫秒
    @Test
    public void BufferedBytes() throws IOException {
        long start = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.close();
        bis.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒");
    }
}

事实证明,带Buffered的就是霸道,再配合指定数据长度读写,效率杠杠的。

PrintStream

先晒张图,System.err和System.out的申明,就是PrintStream。(本篇不打算铺开讲这里的设计,后面有机会再说)。

 官方都在用的东西,自然是好东西。且先看看基本用法:

import java.io.File;
import java.io.PrintStream;

public class Main {
    public static void main(String[] args) throws Exception {
        File file = new File("D:\\data\\data.txt");
        PrintStream ps = new PrintStream(file);
        ps.println("jordan");
        ps.println(1);
        ps.print('1');
        ps.close();
    }

 很简洁!以下的println()和print(),均将内容打印到File中去了,我们上面说了,这是个好东西,简洁只是“好”的一方面,继续查看源码,追踪print函数,我们会发现:

这里原来运用了装饰模式,将变量textOut申明为字符流BufferedWriter,所以我们调用print()和println()方法,实际是调用了BufferedWriter中的

write(String s, int off, int len)
write(char cbuf[], int off, int len)

上面的那些Buffer,一层层的套,写着多麻烦,有了PrintStream,还要啥自行车,功能增强,它不香吗?对咯,我们在这里可以先把字符流的一些活儿给干咯,比如要指定字符集,直接这样就可以了:

 PrintStream ps = new PrintStream(new FileOutputStream(file), false, StandardCharsets.ISO_8859_1.name());

字符流

FileReader&FileWriter&BufferedReader&BufferedWriter&

PrintWriter

字符流FileReader和FileWriter的用法分别对应字节流的FileInputStream和FileOutputStream。BufferedReader和BufferedWriter的用法则对应字节流的BufferedInputStream和BufferedOutputStream。而PrintWiter其实在PrintStream中已经运用过了。这里也跟上面一样,做了下读写文件的效率对比(这里的文本数据文件大小为2043KB,如果你的文件越大,效果就会越明显。)。另外,如果要将内容打印到控制台,且看到String类型的结果,那么你需要将char类型的数据进行一次转换后再打印。

import org.junit.Before;
import org.junit.Test;

import java.io.*;

public class EfficiencyCompare {
    private File inFile = new File("E:/data/javaIO/a.csv");
    private File outFile = new File("E:/data/javaIO/b.csv");

    @Before
    public void init() throws IOException {
        if (!outFile.exists()) {
            boolean res = outFile.createNewFile();
            System.out.println(res);
        }
    }

    // 共耗时541毫秒。
    @Test
    public void NoBufferedChar() throws IOException {
        long start = System.currentTimeMillis();
        FileReader fr = new FileReader(inFile);
        FileWriter fw = new FileWriter(outFile);
        int ch = 0;
        while ((ch = fr.read()) != -1) {
            fw.write(ch);
        }
        fw.close();
        fr.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }

    // 共耗时87毫秒。
    @Test
    public void NoBufferedChars() throws IOException {
        long start = System.currentTimeMillis();
        FileReader fr = new FileReader(inFile);
        FileWriter fw = new FileWriter(outFile);
        int ch = 0;
        char[] chars = new char[1024];
        while ((ch = fr.read(chars)) != -1) {
            fw.write(chars, 0, ch);
        }
        fw.close();
        fr.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }

    // 共耗时235毫秒。
    @Test
    public void BufferedChar() throws IOException {
        long start = System.currentTimeMillis();
        BufferedReader br = new BufferedReader(new FileReader(inFile));
        BufferedWriter bw = new BufferedWriter(new FileWriter(outFile));
        int ch = 0;
        while ((ch = br.read()) != -1) {
            bw.write(ch);
        }
        bw.close();
        br.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }

    // 共耗时77毫秒。
    @Test
    public void BufferedChars() throws IOException {
        long start = System.currentTimeMillis();
        BufferedReader br = new BufferedReader(new FileReader(inFile));
        BufferedWriter bw = new BufferedWriter(new FileWriter(outFile));
        int len = 0;
        char[] chars = new char[1024];
        while ((len = br.read(chars)) != -1) {
            bw.write(chars, 0, len);
        }
        bw.close();
        br.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }
}

字节流和字符流之间的转换

我们不难发现,如果一个文本要转码写入另一个文件,比如原先为UTF-8编码,现写入的文件却要用GBK编码。或者,你要读取(写入)的一个文件为非IO流默认编码。此时,我们的转换流就开始发挥作用了。

InputStreamReader--接收FileInputStream和编码格式--FileReader的父类

OutputStreamWriter--接收FileOutputStream和编码格式--FileWriter的父类

下面来看看对它的使用:

import org.junit.Before;
import org.junit.Test;

import java.io.*;

public class ISRAndOSW {
    private File inFile = new File("E:/data/javaIO/a.csv");
    private File outFile = new File("E:/data/javaIO/b.csv");

    @Before
    public void init() throws IOException {
        if (!outFile.exists()) {
            boolean res = outFile.createNewFile();
            System.out.println(res);
        }
    }

    // 共耗时115毫秒。
    @Test
    public void NoBufferedChar() throws IOException {
        long start = System.currentTimeMillis();
        InputStreamReader isr = new InputStreamReader(new FileInputStream(inFile), "UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile), "GBK");
        char[] chars = new char[1024];
        int len = 0;
        while ((len = isr.read(chars)) != -1) {
            osw.write(chars, 0, len);
        }
        osw.close();
        isr.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }

    // 共耗时85毫秒。
    @Test
    public void BufferedChars() throws IOException {
        long start = System.currentTimeMillis();
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile), "UTF-8"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "GBK"));
        int len = 0;
        char[] chars = new char[1024];
        while ((len = br.read(chars)) != -1) {
            bw.write(chars, 0, len);
        }
        bw.close();
        br.close();
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end - start) + "毫秒。");
    }


}

在使用IO流读取和写入文本文件时,最好是使用字符流BufferedReader、BufferedWriter去接收一个InputStreamReader、OutputStreamWriter的输出。也就是上面代码的第二种方式。这样可以在使用转换流的时候指定你的编码格式,有效避免乱码问题。

如果在转换过程中,字节流也用上buffer以更好的提升效率,那么这部分代码将变成这样:

import java.io.*;
import java.nio.charset.StandardCharsets;

public class Main {
    public static void main(String[] args) throws Exception {
        File file = new File("D:\\data\\data.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), StandardCharsets.UTF_8));
        char[] chars = new char[1024];
        int len = 0;
        while ((len = br.read(chars)) != -1) {
            System.out.println(new String(chars, 0, len));
        }
        br.close();
    }
}

这一句:BufferedReader br = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), StandardCharsets.UTF_8));仿佛俄罗斯套娃一般,相对应的,BufferedWriter和输出流的写法,也类似。

综上,从简洁和效率上来说,输出流直接使用PrintStream是更明智的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柏舟飞流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值